diff --git a/.dockerignore b/.dockerignore index 4bb2469b09e25..e778fce267438 100644 --- a/.dockerignore +++ b/.dockerignore @@ -11,3 +11,19 @@ cmd/**/debug debug.test coverage.out ui/node_modules/ +test-results/ +test/ +manifests/ +hack/ +docs/ +examples/ +.github/ +!test/container +!test/e2e/testdata +!test/fixture +!test/remote +!hack/installers +!hack/gpg-wrapper.sh +!hack/git-verify-wrapper.sh +!hack/tool-versions.sh +!hack/install.sh \ No newline at end of file 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/cherry-pick-bot.yml b/.github/cherry-pick-bot.yml new file mode 100644 index 0000000000000..a9de2afd04927 --- /dev/null +++ b/.github/cherry-pick-bot.yml @@ -0,0 +1,3 @@ +enabled: true +preservePullRequestTitle: true + diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6e66e66db6630..5540fb7fd93e6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -16,3 +16,28 @@ updates: directory: "/ui/" schedule: interval: "daily" + + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "daily" + + - package-ecosystem: "docker" + directory: "/test/container/" + schedule: + interval: "daily" + + - package-ecosystem: "docker" + directory: "/test/e2e/multiarch-container/" + schedule: + interval: "daily" + + - package-ecosystem: "docker" + directory: "/test/remote/" + schedule: + interval: "daily" + + - package-ecosystem: "docker" + directory: "/ui-test/" + schedule: + interval: "daily" diff --git a/.github/pr-title-checker-config.json b/.github/pr-title-checker-config.json new file mode 100644 index 0000000000000..c3437def33834 --- /dev/null +++ b/.github/pr-title-checker-config.json @@ -0,0 +1,15 @@ +{ + "LABEL": { + "name": "title needs formatting", + "color": "EEEEEE" + }, + "CHECKS": { + "prefixes": ["[Bot] docs: "], + "regexp": "^(feat|fix|docs|test|ci|chore)!?(\\(.*\\))?!?:.*" + }, + "MESSAGES": { + "success": "PR title is valid", + "failure": "PR title is invalid", + "notice": "PR Title needs to pass regex '^(feat|fix|docs|test|ci|chore)!?(\\(.*\\))?!?:.*" + } + } diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index e64d61328d9f1..c1a3f42508aaa 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,17 +1,24 @@ + Checklist: * [ ] Either (a) I've created an [enhancement proposal](https://github.com/argoproj/argo-cd/issues/new/choose) and discussed it with the community, (b) this is a bug fix, or (c) this does not need to be in the release notes. * [ ] The title of the PR states what changed and the related issues number (used for the release note). +* [ ] The title of the PR conforms to the [Toolchain Guide](https://argo-cd.readthedocs.io/en/latest/developer-guide/toolchain-guide/#title-of-the-pr) * [ ] I've included "Closes [ISSUE #]" or "Fixes [ISSUE #]" in the description to automatically close the associated issue. * [ ] 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/tree/master/community#contributing-to-argo) +* [ ] 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 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/README.md b/.github/workflows/README.md new file mode 100644 index 0000000000000..6d4302d2b540c --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,38 @@ +# Workflows + +| Workflow | Description | +|--------------------|----------------------------------------------------------------| +| ci-build.yaml | Build, lint, test, codegen, build-ui, analyze, e2e-test | +| codeql.yaml | CodeQL analysis | +| image-reuse.yaml | Build, push, and Sign container images | +| image.yaml | Build container image for PR's & publish for push events | +| pr-title-check.yaml| Lint PR for semantic information | +| init-release.yaml | Build manifests and version then create a PR for release branch| +| release.yaml | Build images, cli-binaries, provenances, and post actions | +| update-snyk.yaml | Scheduled snyk reports | + +# Reusable workflows + +## image-reuse.yaml + +- The resuable workflow can be used to publish or build images with multiple container registries(Quay,GHCR, dockerhub), and then sign them with cosign when an image is published. +- A GO version `must` be specified e.g. 1.21 +- The image name for each registry *must* contain the tag. Note: multiple tags are allowed for each registry using a CSV type. +- Multiple platforms can be specified e.g. linux/amd64,linux/arm64 +- Images are not published by default. A boolean value must be set to `true` to push images. +- An optional target can be specified. + +| Inputs | Description | Type | Required | Defaults | +|-------------------|-------------------------------------|-------------|----------|-----------------| +| go-version | Version of Go to be used | string | true | none | +| quay_image_name | Full image name and tag | CSV, string | false | none | +| ghcr_image_name | Full image name and tag | CSV, string | false | none | +| docker_image_name | Full image name and tag | CSV, string | false | none | +| platforms | Platforms to build (linux/amd64) | CSV, string | false | linux/amd64 | +| push | Whether to push image/s to registry | boolean | false | false | +| target | Target build stage | string | false | none | + +| Outputs | Description | Type | +|-------------|------------------------------------------|-------| +|image-digest | Image digest of image container created | string| + diff --git a/.github/workflows/ci-build.yaml b/.github/workflows/ci-build.yaml index 87b1b0917b5cc..84534d518f26b 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' @@ -9,10 +9,11 @@ on: pull_request: branches: - 'master' + - 'release-*' env: # Golang version to use across CI steps - GOLANG_VERSION: '1.18' + GOLANG_VERSION: '1.21' concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -22,36 +23,62 @@ permissions: contents: read jobs: + changes: + runs-on: ubuntu-latest + outputs: + backend: ${{ steps.filter.outputs.backend_any_changed }} + frontend: ${{ steps.filter.outputs.frontend_any_changed }} + steps: + - uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 + - uses: tj-actions/changed-files@90a06d6ba9543371ab4df8eeca0be07ca6054959 # v42.0.2 + id: filter + with: + # Any file which is not under docs/, ui/ or is not a markdown file is counted as a backend file + files_yaml: | + backend: + - '!ui/**' + - '!**.md' + - '!**/*.md' + - '!docs/**' + frontend: + - 'ui/**' + - Dockerfile 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@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 - name: Setup Golang - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0 with: go-version: ${{ env.GOLANG_VERSION }} - name: Download all Go modules run: | go mod download - - name: Check for tidyness of go.mod and go.sum + - name: Check for tidiness of go.mod and go.sum run: | go mod tidy git diff --exit-code -- . 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@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 - name: Setup Golang - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0 with: go-version: ${{ env.GOLANG_VERSION }} - name: Restore go build cache - uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: ~/.cache/go-build key: ${{ runner.os }}-go-build-v1-${{ github.run_id }} @@ -66,37 +93,42 @@ 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@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 - name: Setup Golang - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0 with: go-version: ${{ env.GOLANG_VERSION }} - name: Run golangci-lint - uses: golangci/golangci-lint-action@0ad9a0988b3973e851ab0a07adf248ec2e100376 # v3.3.1 + uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 with: - version: v1.46.2 - args: --timeout 10m --exclude SA5011 --verbose + version: v1.54.0 + args: --enable gofmt --timeout 10m --exclude SA5011 --verbose --max-issues-per-linter 0 --max-same-issues 0 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 - name: Checkout code - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 - name: Create symlink in GOPATH run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd - name: Setup Golang - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0 with: go-version: ${{ env.GOLANG_VERSION }} - name: Install required packages @@ -116,13 +148,17 @@ jobs: run: | echo "/usr/local/bin" >> $GITHUB_PATH - name: Restore go build cache - uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: ~/.cache/go-build key: ${{ runner.os }}-go-build-v1-${{ github.run_id }} - name: Install all tools required for building & testing run: | make install-test-tools-local + # We install kustomize in the dist directory + - name: Add dist to PATH + run: | + echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH - name: Setup git username and email run: | git config --global user.name "John Doe" @@ -133,33 +169,35 @@ jobs: - name: Run all unit tests run: make test-local - name: Generate code coverage artifacts - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 with: name: code-coverage path: coverage.out - name: Generate test results artifacts - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 with: name: test-results path: test-results/ test-go-race: - name: Run unit tests with -race, for Go packages + 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 - name: Checkout code - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 - name: Create symlink in GOPATH run: ln -s $(pwd) ~/go/src/github.com/argoproj/argo-cd - name: Setup Golang - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0 with: go-version: ${{ env.GOLANG_VERSION }} - name: Install required packages @@ -179,13 +217,17 @@ jobs: run: | echo "/usr/local/bin" >> $GITHUB_PATH - name: Restore go build cache - uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: ~/.cache/go-build key: ${{ runner.os }}-go-build-v1-${{ github.run_id }} - name: Install all tools required for building & testing run: | make install-test-tools-local + # We install kustomize in the dist directory + - name: Add dist to PATH + run: | + echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH - name: Setup git username and email run: | git config --global user.name "John Doe" @@ -196,19 +238,22 @@ jobs: - name: Run all unit tests run: make test-race-local - name: Generate test results artifacts - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 with: name: race-results path: test-results/ 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@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 - name: Setup Golang - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0 with: go-version: ${{ env.GOLANG_VERSION }} - name: Create symlink in GOPATH @@ -232,6 +277,10 @@ jobs: make install-codegen-tools-local make install-go-tools-local working-directory: /home/runner/go/src/github.com/argoproj/argo-cd + # We install kustomize in the dist directory + - name: Add dist to PATH + run: | + echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH - name: Run codegen run: | set -x @@ -247,17 +296,20 @@ 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@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 - name: Setup NodeJS - uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 + uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 with: - node-version: '12.18.4' + node-version: '21.6.1' - name: Restore node dependency cache id: cache-dependencies - uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: ui/node_modules key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }} @@ -279,20 +331,22 @@ 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: - name: Checkout code - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 with: fetch-depth: 0 - name: Restore node dependency cache id: cache-dependencies - uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: ui/node_modules key: ${{ runner.os }}-node-dep-v2-${{ hashFiles('**/yarn.lock') }} @@ -302,7 +356,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 @@ -312,7 +366,7 @@ jobs: name: test-results path: test-results - name: Upload code coverage information to codecov.io - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 + uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4 with: file: coverage.out - name: Perform static code analysis using SonarCloud @@ -323,34 +377,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.26.0, v1.25.4, v1.24.3, v1.23.3] - 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" @@ -360,15 +417,15 @@ 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@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 - name: Setup Golang - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0 with: go-version: ${{ env.GOLANG_VERSION }} - name: GH actions workaround - Kill XSP4 process @@ -384,9 +441,10 @@ jobs: sudo mkdir -p $HOME/.kube && sudo chown -R runner $HOME/.kube sudo k3s kubectl config view --raw > $HOME/.kube/config sudo chown runner $HOME/.kube/config + sudo chmod go-r $HOME/.kube/config kubectl version - name: Restore go build cache - uses: actions/cache@58c146cc91c5b9e778e71775dfe9bf1442ad9a12 # v3.2.3 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: ~/.cache/go-build key: ${{ runner.os }}-go-build-v1-${{ github.run_id }} @@ -412,9 +470,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.35.3 + docker pull ghcr.io/dexidp/dex:v2.38.0 docker pull argoproj/argo-cd-ci-builder:v1.0.0 - docker pull redis:7.0.7-alpine + docker pull redis:7.0.14-alpine - name: Create target directory for binaries in the build-process run: | mkdir -p dist @@ -442,8 +500,31 @@ jobs: set -x make test-e2e-local - name: Upload e2e-server logs - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 with: 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 09b941f00a119..5d745d222d2fb 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -5,6 +5,7 @@ on: # Secrets aren't available for dependabot on push. https://docs.github.com/en/enterprise-cloud@latest/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/troubleshooting-the-codeql-workflow#error-403-resource-not-accessible-by-integration-when-using-dependabot branches-ignore: - 'dependabot/**' + - 'cherry-pick-*' pull_request: schedule: - cron: '0 19 * * 0' @@ -26,10 +27,15 @@ jobs: # CodeQL runs on ubuntu-latest and windows-latest runs-on: ubuntu-22.04 - steps: - name: Checkout repository - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # 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 new file mode 100644 index 0000000000000..5b5a12b346fa1 --- /dev/null +++ b/.github/workflows/image-reuse.yaml @@ -0,0 +1,171 @@ +name: Publish and Sign Container Image +on: + workflow_call: + inputs: + go-version: + required: true + type: string + quay_image_name: + required: false + type: string + ghcr_image_name: + required: false + type: string + docker_image_name: + required: false + type: string + platforms: + required: true + type: string + default: linux/amd64 + push: + required: true + type: boolean + default: false + target: + required: false + type: string + + secrets: + quay_username: + required: false + quay_password: + required: false + ghcr_username: + required: false + ghcr_password: + required: false + docker_username: + required: false + docker_password: + required: false + + outputs: + image-digest: + description: "sha256 digest of container image" + value: ${{ jobs.publish.outputs.image-digest }} + +permissions: {} + +jobs: + publish: + permissions: + contents: read + packages: write # Used to push images to `ghcr.io` if used. + id-token: write # Needed to create an OIDC token for keyless signing + runs-on: ubuntu-22.04 + outputs: + image-digest: ${{ steps.image.outputs.digest }} + steps: + - name: Checkout code + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + if: ${{ github.ref_type == 'tag'}} + + - name: Checkout code + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 + if: ${{ github.ref_type != 'tag'}} + + - name: Setup Golang + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 + with: + go-version: ${{ inputs.go-version }} + + - name: Install cosign + uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 # v3.4.0 + + - uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7 # v2.2.0 + - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + + - name: Setup tags for container image as a CSV type + run: | + IMAGE_TAGS=$(for str in \ + ${{ inputs.quay_image_name }} \ + ${{ inputs.ghcr_image_name }} \ + ${{ inputs.docker_image_name}}; do + echo -n "${str}",;done | sed 's/,$//') + + echo $IMAGE_TAGS + echo "TAGS=$IMAGE_TAGS" >> $GITHUB_ENV + + - name: Setup image namespace for signing, strip off the tag + run: | + TAGS=$(for tag in \ + ${{ inputs.quay_image_name }} \ + ${{ inputs.ghcr_image_name }} \ + ${{ inputs.docker_image_name}}; do + echo -n "${tag}" | awk -F ":" '{print $1}' -;done) + + echo $TAGS + echo 'SIGNING_TAGS<> $GITHUB_ENV + echo $TAGS >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV + + - name: Login to Quay.io + uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 + with: + registry: quay.io + username: ${{ secrets.quay_username }} + password: ${{ secrets.quay_password }} + if: ${{ inputs.quay_image_name && inputs.push }} + + - name: Login to GitHub Container Registry + uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 + with: + registry: ghcr.io + username: ${{ secrets.ghcr_username }} + password: ${{ secrets.ghcr_password }} + if: ${{ inputs.ghcr_image_name && inputs.push }} + + - name: Login to dockerhub Container Registry + uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 + with: + username: ${{ secrets.docker_username }} + password: ${{ secrets.docker_password }} + if: ${{ inputs.docker_image_name && inputs.push }} + + - name: Set up build args for container image + run: | + echo "GIT_TAG=$(if [ -z "`git status --porcelain`" ]; then git describe --exact-match --tags HEAD 2>/dev/null; fi)" >> $GITHUB_ENV + echo "GIT_COMMIT=$(git rev-parse HEAD)" >> $GITHUB_ENV + echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV + echo "GIT_TREE_STATE=$(if [ -z "`git status --porcelain`" ]; then echo "clean" ; else echo "dirty"; fi)" >> $GITHUB_ENV + + - name: Free Disk Space (Ubuntu) + uses: jlumbroso/free-disk-space@4d9e71b726748f254fe64fa44d273194bd18ec91 + with: + large-packages: false + docker-images: false + swap-storage: false + tool-cache: false + + - name: Build and push container image + id: image + uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 #v5.3.0 + with: + context: . + platforms: ${{ inputs.platforms }} + push: ${{ inputs.push }} + tags: ${{ env.TAGS }} + target: ${{ inputs.target }} + provenance: false + sbom: false + build-args: | + GIT_TAG=${{env.GIT_TAG}} + GIT_COMMIT=${{env.GIT_COMMIT}} + BUILD_DATE=${{env.BUILD_DATE}} + GIT_TREE_STATE=${{env.GIT_TREE_STATE}} + + - name: Sign container images + run: | + for signing_tag in $SIGNING_TAGS; do + cosign sign \ + -a "repo=${{ github.repository }}" \ + -a "workflow=${{ github.workflow }}" \ + -a "sha=${{ github.sha }}" \ + -y \ + "$signing_tag"@${{ steps.image.outputs.digest }} + done + if: ${{ inputs.push }} diff --git a/.github/workflows/image.yaml b/.github/workflows/image.yaml index 6da3eac6ed670..a7174e10de9db 100644 --- a/.github/workflows/image.yaml +++ b/.github/workflows/image.yaml @@ -9,97 +9,109 @@ on: - master types: [ labeled, unlabeled, opened, synchronize, reopened ] -env: - GOLANG_VERSION: '1.18' - concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -permissions: - contents: read +permissions: {} jobs: - publish: + set-vars: permissions: - contents: write # for git to push upgrade commit if not already deployed - packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags + contents: read if: github.repository == 'argoproj/argo-cd' runs-on: ubuntu-22.04 - env: - GOPATH: /home/runner/work/argo-cd/argo-cd + outputs: + image-tag: ${{ steps.image.outputs.tag}} + platforms: ${{ steps.platforms.outputs.platforms }} steps: - - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 - with: - go-version: ${{ env.GOLANG_VERSION }} - - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 - with: - path: src/github.com/argoproj/argo-cd + - uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 - # get image tag - - run: echo "tag=$(cat ./VERSION)-${GITHUB_SHA::8}" >> $GITHUB_OUTPUT - working-directory: ./src/github.com/argoproj/argo-cd + - name: Set image tag for ghcr + run: echo "tag=$(cat ./VERSION)-${GITHUB_SHA::8}" >> $GITHUB_OUTPUT id: image - # login - - run: | - docker login ghcr.io --username $USERNAME --password-stdin <<< "$PASSWORD" - docker login quay.io --username "$DOCKER_USERNAME" --password-stdin <<< "$DOCKER_TOKEN" - if: github.event_name == 'push' - env: - USERNAME: ${{ github.actor }} - PASSWORD: ${{ secrets.GITHUB_TOKEN }} - DOCKER_USERNAME: ${{ secrets.RELEASE_QUAY_USERNAME }} - DOCKER_TOKEN: ${{ secrets.RELEASE_QUAY_TOKEN }} - - # build - - uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0 - - uses: docker/setup-buildx-action@8c0edbc76e98fa90f69d9a2c020dcb50019dc325 # v2.2.1 - - run: | + - name: Determine image platforms to use + id: platforms + run: | IMAGE_PLATFORMS=linux/amd64 - if [[ "${{ github.event_name }}" == "push" || "${{ contains(github.event.pull_request.labels.*.name, 'test-arm-image') }}" == "true" ]] + if [[ "${{ github.event_name }}" == "push" || "${{ contains(github.event.pull_request.labels.*.name, 'test-multi-image') }}" == "true" ]] then IMAGE_PLATFORMS=linux/amd64,linux/arm64,linux/s390x,linux/ppc64le fi echo "Building image for platforms: $IMAGE_PLATFORMS" - docker buildx build --platform $IMAGE_PLATFORMS --sbom=false --provenance=false --push="${{ github.event_name == 'push' }}" \ - -t ghcr.io/argoproj/argo-cd/argocd:${{ steps.image.outputs.tag }} \ - -t quay.io/argoproj/argocd:latest . - working-directory: ./src/github.com/argoproj/argo-cd - - # sign container images - - name: Install cosign - uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.8.1 - with: - cosign-release: 'v1.13.1' + echo "platforms=$IMAGE_PLATFORMS" >> $GITHUB_OUTPUT - - name: Install crane to get digest of image - uses: imjasonh/setup-crane@e82f1b9a8007d399333baba4d75915558e9fb6a4 + build-only: + needs: [set-vars] + permissions: + contents: read + packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags + id-token: write # for creating OIDC tokens for signing. + if: ${{ github.repository == 'argoproj/argo-cd' && github.event_name != 'push' }} + uses: ./.github/workflows/image-reuse.yaml + with: + # Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations) + go-version: 1.21 + platforms: ${{ needs.set-vars.outputs.platforms }} + push: false - - name: Get digest of image - run: | - echo "IMAGE_DIGEST=$(crane digest quay.io/argoproj/argocd:latest)" >> $GITHUB_ENV + build-and-publish: + needs: [set-vars] + permissions: + contents: read + packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags + id-token: write # for creating OIDC tokens for signing. + if: ${{ github.repository == 'argoproj/argo-cd' && github.event_name == 'push' }} + uses: ./.github/workflows/image-reuse.yaml + with: + quay_image_name: quay.io/argoproj/argocd:latest + ghcr_image_name: ghcr.io/argoproj/argo-cd/argocd:${{ needs.set-vars.outputs.image-tag }} + # Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations) + go-version: 1.21 + platforms: ${{ needs.set-vars.outputs.platforms }} + push: true + secrets: + quay_username: ${{ secrets.RELEASE_QUAY_USERNAME }} + quay_password: ${{ secrets.RELEASE_QUAY_TOKEN }} + ghcr_username: ${{ github.actor }} + ghcr_password: ${{ secrets.GITHUB_TOKEN }} - - name: Sign Argo CD latest image - run: | - cosign sign --key env://COSIGN_PRIVATE_KEY quay.io/argoproj/argocd@${{ env.IMAGE_DIGEST }} - # Displays the public key to share. - cosign public-key --key env://COSIGN_PRIVATE_KEY - env: - COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}} - COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}} - if: ${{ github.event_name == 'push' }} + build-and-publish-provenance: # Push attestations to GHCR, latest image is polluting quay.io + needs: + - build-and-publish + permissions: + actions: read # for detecting the Github Actions environment. + id-token: write # for creating OIDC tokens for signing. + packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues) + if: ${{ github.repository == 'argoproj/argo-cd' && github.event_name == 'push' }} + # 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_container_slsa3.yml@v1.10.0 + with: + image: ghcr.io/argoproj/argo-cd/argocd + digest: ${{ needs.build-and-publish.outputs.image-digest }} + registry-username: ${{ github.actor }} + secrets: + registry-password: ${{ secrets.GITHUB_TOKEN }} - # deploy + Deploy: + needs: + - build-and-publish + - set-vars + permissions: + contents: write # for git to push upgrade commit if not already deployed + packages: write # for pushing packages to GHCR, which is used by cd.apps.argoproj.io to avoid polluting Quay with tags + if: ${{ github.repository == 'argoproj/argo-cd' && github.event_name == 'push' }} + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 - run: git clone "https://$TOKEN@github.com/argoproj/argoproj-deployments" - if: github.event_name == 'push' env: TOKEN: ${{ secrets.TOKEN }} - run: | - docker run -u $(id -u):$(id -g) -v $(pwd):/src -w /src --rm -t ghcr.io/argoproj/argo-cd/argocd:${{ steps.image.outputs.tag }} kustomize edit set image quay.io/argoproj/argocd=ghcr.io/argoproj/argo-cd/argocd:${{ steps.image.outputs.tag }} + docker run -u $(id -u):$(id -g) -v $(pwd):/src -w /src --rm -t ghcr.io/argoproj/argo-cd/argocd:${{ needs.set-vars.outputs.image-tag }} kustomize edit set image quay.io/argoproj/argocd=ghcr.io/argoproj/argo-cd/argocd:${{ needs.set-vars.outputs.image-tag }} git config --global user.email 'ci@argoproj.com' git config --global user.name 'CI' - git diff --exit-code && echo 'Already deployed' || (git commit -am 'Upgrade argocd to ${{ steps.image.outputs.tag }}' && git push) - if: github.event_name == 'push' + git diff --exit-code && echo 'Already deployed' || (git commit -am 'Upgrade argocd to ${{ needs.set-vars.outputs.image-tag }}' && git push) working-directory: argoproj-deployments/argocd - # TODO: clean up old images once github supports it: https://github.community/t5/How-to-use-Git-and-GitHub/Deleting-images-from-GitHub-Package-Registry/m-p/41202/thread-id/9811 + diff --git a/.github/workflows/init-release.yaml b/.github/workflows/init-release.yaml new file mode 100644 index 0000000000000..0a0430f27f96b --- /dev/null +++ b/.github/workflows/init-release.yaml @@ -0,0 +1,77 @@ +name: Init ArgoCD Release +on: + workflow_dispatch: + inputs: + TARGET_BRANCH: + description: 'TARGET_BRANCH to checkout (e.g. release-2.5)' + required: true + type: string + + TARGET_VERSION: + description: 'TARGET_VERSION to build manifests (e.g. 2.5.0-rc1) Note: the `v` prefix is not used' + required: true + type: string + +permissions: {} + +jobs: + prepare-release: + permissions: + contents: write # for peter-evans/create-pull-request to create branch + pull-requests: write # for peter-evans/create-pull-request to create a PR + name: Automatically generate version and manifests on ${{ inputs.TARGET_BRANCH }} + runs-on: ubuntu-22.04 + steps: + - name: Checkout code + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + ref: ${{ inputs.TARGET_BRANCH }} + + - name: Check if TARGET_VERSION is well formed. + run: | + set -xue + # Target version must not contain 'v' prefix + if echo "${{ inputs.TARGET_VERSION }}" | grep -e '^v'; then + echo "::error::Target version '${{ inputs.TARGET_VERSION }}' should not begin with a 'v' prefix, refusing to continue." >&2 + exit 1 + fi + + - name: Create VERSION information + run: | + set -ue + echo "Bumping version from $(cat VERSION) to ${{ inputs.TARGET_VERSION }}" + echo "${{ inputs.TARGET_VERSION }}" > VERSION + + # We install kustomize in the dist directory + - name: Add dist to PATH + run: | + echo "/home/runner/work/argo-cd/argo-cd/dist" >> $GITHUB_PATH + + - name: Generate new set of manifests + run: | + set -ue + make install-codegen-tools-local + make manifests-local VERSION=${{ inputs.TARGET_VERSION }} + git diff + + - name: Generate version compatibility table + run: | + git stash + bash hack/update-supported-versions.sh + git add -u . + git stash pop + + - name: Create pull request + uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # v5.0.2 + with: + commit-message: "Bump version to ${{ inputs.TARGET_VERSION }}" + title: "Bump version to ${{ inputs.TARGET_VERSION }} on ${{ inputs.TARGET_BRANCH }} branch" + body: Updating VERSION and manifests to ${{ inputs.TARGET_VERSION }} + branch: update-version + branch-suffix: random + signoff: true + labels: release + + diff --git a/.github/workflows/pr-title-check.yml b/.github/workflows/pr-title-check.yml index 4c11903ac9504..020535d7b8afa 100644 --- a/.github/workflows/pr-title-check.yml +++ b/.github/workflows/pr-title-check.yml @@ -2,15 +2,11 @@ name: "Lint PR" on: pull_request_target: - types: - - opened - - edited - - synchronize + types: [opened, edited, reopened, synchronize] # IMPORTANT: No checkout actions, scripts, or builds should be added to this workflow. Permissions should always be used -# with extreme caution. -permissions: - contents: read +# with extreme caution. https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target +permissions: {} # PR updates can happen in quick succession leading to this # workflow being trigger a number of times. This limits it @@ -18,24 +14,16 @@ permissions: concurrency: group: ${{ github.workflow }}-${{ github.ref }} + jobs: - main: + validate: permissions: - pull-requests: read # for amannn/action-semantic-pull-request to analyze PRs - statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR - name: Validate PR title + contents: read + pull-requests: read + name: Validate PR Title runs-on: ubuntu-latest steps: - # IMPORTANT: Carefully review changes when updating this action. Using the pull_request_target event requires caution. - - uses: amannn/action-semantic-pull-request@01d5fd8a8ebb9aafe902c40c53f0f4744f7381eb # v5.0.2 + - uses: thehanimo/pr-title-checker@0cf5902181e78341bb97bb06646396e5bd354b3f # v1.4.0 with: - types: | - feat - fix - docs - test - ci - chore - [Bot] docs - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + configuration_path: ".github/pr-title-checker-config.json" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6899fedff51f7..d332c075d0bd0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,266 +1,161 @@ -name: Create ArgoCD release +name: Publish ArgoCD Release on: push: tags: - - "release-v*" - - "!release-v1.5*" - - "!release-v1.4*" - - "!release-v1.3*" - - "!release-v1.2*" - - "!release-v1.1*" - - "!release-v1.0*" - - "!release-v0*" + - 'v*' + - '!v2.4*' + - '!v2.5*' + - '!v2.6*' -env: - GOLANG_VERSION: '1.18' +permissions: {} -permissions: - contents: read +env: + GOLANG_VERSION: '1.21' # Note: go-version must also be set in job argocd-image.with.go-version jobs: - prepare-release: + argocd-image: + permissions: + contents: read + id-token: write # for creating OIDC tokens for signing. + packages: write # used to push images to `ghcr.io` if used. + if: github.repository == 'argoproj/argo-cd' + uses: ./.github/workflows/image-reuse.yaml + with: + quay_image_name: quay.io/argoproj/argocd:${{ github.ref_name }} + # Note: cannot use env variables to set go-version (https://docs.github.com/en/actions/using-workflows/reusing-workflows#limitations) + go-version: 1.21 + platforms: linux/amd64,linux/arm64,linux/s390x,linux/ppc64le + push: true + secrets: + quay_username: ${{ secrets.RELEASE_QUAY_USERNAME }} + quay_password: ${{ secrets.RELEASE_QUAY_TOKEN }} + + argocd-image-provenance: + needs: [argocd-image] + permissions: + actions: read # for detecting the Github Actions environment. + id-token: write # for creating OIDC tokens for signing. + 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.10.0 + with: + image: quay.io/argoproj/argocd + digest: ${{ needs.argocd-image.outputs.image-digest }} + secrets: + registry-username: ${{ secrets.RELEASE_QUAY_USERNAME }} + registry-password: ${{ secrets.RELEASE_QUAY_TOKEN }} + + goreleaser: + needs: + - argocd-image + - argocd-image-provenance permissions: - contents: write # To push changes to release branch - name: Perform automatic release on trigger ${{ github.ref }} + contents: write # used for uploading assets if: github.repository == 'argoproj/argo-cd' runs-on: ubuntu-22.04 - env: - # The name of the tag as supplied by the GitHub event - SOURCE_TAG: ${{ github.ref }} - # The image namespace where Docker image will be published to - IMAGE_NAMESPACE: quay.io/argoproj - # Whether to create & push image and release assets - DRY_RUN: false - # Whether a draft release should be created, instead of public one - DRAFT_RELEASE: false - # Whether to update homebrew with this release as well - # Set RELEASE_HOMEBREW_TOKEN secret in repository for this to work - needs - # access to public repositories - UPDATE_HOMEBREW: false - # Name of the GitHub user for Git config - GIT_USERNAME: argo-bot - # E-Mail of the GitHub user for Git config - GIT_EMAIL: argoproj@gmail.com + outputs: + hashes: ${{ steps.hash.outputs.hashes }} + steps: - name: Checkout code - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 with: fetch-depth: 0 token: ${{ secrets.GITHUB_TOKEN }} - - name: Check if the published tag is well formed and setup vars - run: | - set -xue - # Target version must match major.minor.patch and optional -rcX suffix - # where X must be a number. - TARGET_VERSION=${SOURCE_TAG#*release-v} - if ! echo "${TARGET_VERSION}" | egrep '^[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)*$'; then - echo "::error::Target version '${TARGET_VERSION}' is malformed, refusing to continue." >&2 - exit 1 - fi - - # Target branch is the release branch we're going to operate on - # Its name is 'release-.' - TARGET_BRANCH="release-${TARGET_VERSION%\.[0-9]*}" - - # The release tag is the source tag, minus the release- prefix - RELEASE_TAG="${SOURCE_TAG#*release-}" - - # Whether this is a pre-release (indicated by -rc suffix) - PRE_RELEASE=false - if echo "${RELEASE_TAG}" | egrep -- '-rc[0-9]+$'; then - PRE_RELEASE=true - fi - - # We must not have a release trigger within the same release branch, - # because that means a release for this branch is already running. - if git tag -l | grep "release-v${TARGET_VERSION%\.[0-9]*}" | grep -v "release-v${TARGET_VERSION}"; then - echo "::error::Another release for branch ${TARGET_BRANCH} is currently in progress." - exit 1 - fi - - # Ensure that release do not yet exist - if git rev-parse ${RELEASE_TAG}; then - echo "::error::Release tag ${RELEASE_TAG} already exists in repository. Refusing to continue." - exit 1 - fi + - name: Fetch all tags + run: git fetch --force --tags - # Make the variables available in follow-up steps - echo "TARGET_VERSION=${TARGET_VERSION}" >> $GITHUB_ENV - echo "TARGET_BRANCH=${TARGET_BRANCH}" >> $GITHUB_ENV - echo "RELEASE_TAG=${RELEASE_TAG}" >> $GITHUB_ENV - echo "PRE_RELEASE=${PRE_RELEASE}" >> $GITHUB_ENV - - - name: Check if our release tag has a correct annotation + - name: Set GORELEASER_PREVIOUS_TAG # Workaround, GoReleaser uses 'git-describe' to determine a previous tag. Our tags are created in realease branches. run: | - set -ue - # Fetch all tag information as well - git fetch --prune --tags --force - - echo "=========== BEGIN COMMIT MESSAGE =============" - git show ${SOURCE_TAG} - echo "============ END COMMIT MESSAGE ==============" - - # Quite dirty hack to get the release notes from the annotated tag - # into a temporary file. - RELEASE_NOTES=$(mktemp -p /tmp release-notes.XXXXXX) - - prefix=true - begin=false - git show ${SOURCE_TAG} | while read line; do - # Whatever is in commit history for the tag, we only want that - # annotation from our tag. We discard everything else. - if test "$begin" = "false"; then - if echo "$line" | grep -q "tag ${SOURCE_TAG#refs/tags/}"; then begin="true"; fi - continue - fi - if test "$prefix" = "true"; then - if test -z "$line"; then prefix=false; fi - else - if echo "$line" | egrep -q '^commit [0-9a-f]+'; then - break - fi - echo "$line" >> ${RELEASE_NOTES} - fi - done - - # For debug purposes - echo "============BEGIN RELEASE NOTES=================" - cat ${RELEASE_NOTES} - echo "=============END RELEASE NOTES==================" - - # Too short release notes are suspicious. We need at least 100 bytes. - relNoteLen=$(stat -c '%s' $RELEASE_NOTES) - if test $relNoteLen -lt 100; then - echo "::error::No release notes provided in tag annotation (or tag is not annotated)" - exit 1 - fi - - # Check for magic string '## Quick Start' in head of release notes - if ! head -2 ${RELEASE_NOTES} | grep -iq '## Quick Start'; then - echo "::error::Release notes seem invalid, quick start section not found." - exit 1 + set -xue + if echo ${{ github.ref_name }} | grep -E -- '-rc1+$';then + echo "GORELEASER_PREVIOUS_TAG=$(git -c 'versionsort.suffix=-rc' tag --list --sort=version:refname | tail -n 2 | head -n 1)" >> $GITHUB_ENV + else + echo "This is not the first release on the branch, Using GoReleaser defaults" fi - # We store path to temporary release notes file for later reading, we - # need it when creating release. - echo "RELEASE_NOTES=${RELEASE_NOTES}" >> $GITHUB_ENV - - name: Setup Golang - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0 with: go-version: ${{ env.GOLANG_VERSION }} - - name: Setup Git author information - run: | - set -ue - git config --global user.email "${GIT_EMAIL}" - git config --global user.name "${GIT_USERNAME}" - - - name: Checkout corresponding release branch - run: | - set -ue - echo "Switching to release branch '${TARGET_BRANCH}'" - if ! git checkout ${TARGET_BRANCH}; then - echo "::error::Checking out release branch '${TARGET_BRANCH}' for target version '${TARGET_VERSION}' (tagged '${RELEASE_TAG}') failed. Does it exist in repo?" - exit 1 - fi - - - name: Create VERSION information - run: | - set -ue - echo "Bumping version from $(cat VERSION) to ${TARGET_VERSION}" - echo "${TARGET_VERSION}" > VERSION - git commit -m "Bump version to ${TARGET_VERSION}" VERSION - - - name: Generate new set of manifests + - name: Set environment variables for ldflags + id: set_ldflag run: | - set -ue - make install-codegen-tools-local - make manifests-local VERSION=${TARGET_VERSION} - git diff - git commit manifests/ -m "Bump version to ${TARGET_VERSION}" - - - name: Create the release tag - run: | - set -ue - echo "Creating release ${RELEASE_TAG}" - git tag ${RELEASE_TAG} - - - name: Login to docker repositories - env: - DOCKER_USERNAME: ${{ secrets.RELEASE_DOCKERHUB_USERNAME }} - DOCKER_TOKEN: ${{ secrets.RELEASE_DOCKERHUB_TOKEN }} - QUAY_USERNAME: ${{ secrets.RELEASE_QUAY_USERNAME }} - QUAY_TOKEN: ${{ secrets.RELEASE_QUAY_TOKEN }} - run: | - set -ue - docker login quay.io --username "${QUAY_USERNAME}" --password-stdin <<< "${QUAY_TOKEN}" - # Remove the following when Docker Hub is gone - docker login --username "${DOCKER_USERNAME}" --password-stdin <<< "${DOCKER_TOKEN}" - if: ${{ env.DRY_RUN != 'true' }} - - - uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0 - - uses: docker/setup-buildx-action@8c0edbc76e98fa90f69d9a2c020dcb50019dc325 # v2.2.1 - - name: Build and push Docker image for release - run: | - set -ue - git clean -fd - mkdir -p dist/ - docker buildx build --platform linux/amd64,linux/arm64,linux/s390x,linux/ppc64le --sbom=false --provenance=false --push -t ${IMAGE_NAMESPACE}/argocd:v${TARGET_VERSION} -t argoproj/argocd:v${TARGET_VERSION} . - make release-cli - make checksums - chmod +x ./dist/argocd-linux-amd64 - ./dist/argocd-linux-amd64 version --client - if: ${{ env.DRY_RUN != 'true' }} + echo "KUBECTL_VERSION=$(go list -m k8s.io/client-go | head -n 1 | rev | cut -d' ' -f1 | rev)" >> $GITHUB_ENV + echo "GIT_TREE_STATE=$(if [ -z "`git status --porcelain`" ]; then echo "clean" ; else echo "dirty"; fi)" >> $GITHUB_ENV - - name: Install cosign - uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.8.1 + - name: Free Disk Space (Ubuntu) + uses: jlumbroso/free-disk-space@4d9e71b726748f254fe64fa44d273194bd18ec91 with: - cosign-release: 'v1.13.1' - - - name: Install crane to get digest of image - uses: imjasonh/setup-crane@e82f1b9a8007d399333baba4d75915558e9fb6a4 + large-packages: false + docker-images: false + swap-storage: false + tool-cache: false + + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@7ec5c2b0c6cdda6e8bbb49444bc797dd33d74dd8 # v5.0.0 + id: run-goreleaser + with: + version: latest + args: release --clean --timeout 55m + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + KUBECTL_VERSION: ${{ env.KUBECTL_VERSION }} + GIT_TREE_STATE: ${{ env.GIT_TREE_STATE }} - - name: Get digest of image + - name: Generate subject for provenance + id: hash + env: + ARTIFACTS: "${{ steps.run-goreleaser.outputs.artifacts }}" run: | - echo "IMAGE_DIGEST=$(crane digest quay.io/argoproj/argocd:v${TARGET_VERSION})" >> $GITHUB_ENV + set -euo pipefail - - name: Sign Argo CD container images and assets - run: | - cosign sign --key env://COSIGN_PRIVATE_KEY ${IMAGE_NAMESPACE}/argocd@${{ env.IMAGE_DIGEST }} - cosign sign-blob --key env://COSIGN_PRIVATE_KEY ./dist/argocd-${TARGET_VERSION}-checksums.txt > ./dist/argocd-${TARGET_VERSION}-checksums.sig - # Retrieves the public key to release as an asset - cosign public-key --key env://COSIGN_PRIVATE_KEY > ./dist/argocd-cosign.pub - env: - COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}} - COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}} - if: ${{ env.DRY_RUN != 'true' }} + hashes=$(echo $ARTIFACTS | jq --raw-output '.[] | {name, "digest": (.extra.Digest // .extra.Checksum)} | select(.digest) | {digest} + {name} | join(" ") | sub("^sha256:";"")' | base64 -w0) + if test "$hashes" = ""; then # goreleaser < v1.13.0 + checksum_file=$(echo "$ARTIFACTS" | jq -r '.[] | select (.type=="Checksum") | .path') + hashes=$(cat $checksum_file | base64 -w0) + fi + echo "hashes=$hashes" >> $GITHUB_OUTPUT - - name: Read release notes file - id: release-notes - uses: juliangruber/read-file-action@02bbba9876a8f870efd4ad64e3b9088d3fb94d4b # v1.1.6 + goreleaser-provenance: + needs: [goreleaser] + permissions: + actions: read # for detecting the Github Actions environment + id-token: write # Needed for provenance signing and ID + 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.10.0 + with: + base64-subjects: "${{ needs.goreleaser.outputs.hashes }}" + provenance-name: "argocd-cli.intoto.jsonl" + upload-assets: true + + generate-sbom: + name: Create SBOM and generate hash + needs: + - argocd-image + - goreleaser + permissions: + contents: write # Needed for release uploads + outputs: + hashes: ${{ steps.sbom-hash.outputs.hashes}} + if: github.repository == 'argoproj/argo-cd' + runs-on: ubuntu-22.04 + steps: + - name: Checkout code + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 with: - path: ${{ env.RELEASE_NOTES }} - - - name: Push changes to release branch - run: | - set -ue - git push origin ${TARGET_BRANCH} - git push origin ${RELEASE_TAG} + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} - - name: Dry run GitHub release - uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e # v1.1.4 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - id: create_release + - name: Setup Golang + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: - tag_name: ${{ env.RELEASE_TAG }} - release_name: ${{ env.RELEASE_TAG }} - draft: ${{ env.DRAFT_RELEASE }} - prerelease: ${{ env.PRE_RELEASE }} - body: ${{ steps.release-notes.outputs.content }} - if: ${{ env.DRY_RUN == 'true' }} + go-version: ${{ env.GOLANG_VERSION }} - name: Generate SBOM (spdx) id: spdx-builder @@ -273,7 +168,7 @@ jobs: # managers (gomod, yarn, npm). PROJECT_FOLDERS: ".,./ui" # full qualified name of the docker image to be inspected - DOCKER_IMAGE: ${{env.IMAGE_NAMESPACE}}/argocd:v${{env.TARGET_VERSION}} + DOCKER_IMAGE: quay.io/argoproj/argocd:${{ github.ref_name }} run: | yarn install --cwd ./ui go install github.com/spdx/spdx-sbom-generator/cmd/generator@$SPDX_GEN_VERSION @@ -291,43 +186,122 @@ jobs: fi cd /tmp && tar -zcf sbom.tar.gz *.spdx - if: ${{ env.DRY_RUN != 'true' }} - - - name: Sign sbom + + - name: Generate SBOM hash + shell: bash + id: sbom-hash run: | - cosign sign-blob --key env://COSIGN_PRIVATE_KEY /tmp/sbom.tar.gz > /tmp/sbom.tar.gz.sig - env: - COSIGN_PRIVATE_KEY: ${{secrets.COSIGN_PRIVATE_KEY}} - COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}} - if: ${{ env.DRY_RUN != 'true' }} - - - name: Create GitHub release + # sha256sum generates sha256 hash for sbom. + # base64 -w0 encodes to base64 and outputs on a single line. + # sha256sum /tmp/sbom.tar.gz ... | base64 -w0 + echo "hashes=$(sha256sum /tmp/sbom.tar.gz | base64 -w0)" >> "$GITHUB_OUTPUT" + + - name: Upload SBOM uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - name: ${{ env.RELEASE_TAG }} - tag_name: ${{ env.RELEASE_TAG }} - draft: ${{ env.DRAFT_RELEASE }} - prerelease: ${{ env.PRE_RELEASE }} - body: ${{ steps.release-notes.outputs.content }} # Pre-pended to the generated notes files: | - dist/argocd-* /tmp/sbom.tar.gz - /tmp/sbom.tar.gz.sig - if: ${{ env.DRY_RUN != 'true' }} - - - name: Update homebrew formula - env: - HOMEBREW_TOKEN: ${{ secrets.RELEASE_HOMEBREW_TOKEN }} - uses: dawidd6/action-homebrew-bump-formula@02e79d9da43d79efa846d73695b6052cbbdbf48a # v3.8.3 + + sbom-provenance: + needs: [generate-sbom] + permissions: + actions: read # for detecting the Github Actions environment + id-token: write # Needed for provenance signing and ID + 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.10.0 + with: + base64-subjects: "${{ needs.generate-sbom.outputs.hashes }}" + provenance-name: "argocd-sbom.intoto.jsonl" + upload-assets: true + + post-release: + needs: + - argocd-image + - goreleaser + - generate-sbom + permissions: + contents: write # Needed to push commit to update stable tag + pull-requests: write # Needed to create PR for VERSION update. + if: github.repository == 'argoproj/argo-cd' + runs-on: ubuntu-22.04 + steps: + - name: Checkout code + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 with: - token: ${{env.HOMEBREW_TOKEN}} - formula: argocd - if: ${{ env.HOMEBREW_TOKEN != '' && env.UPDATE_HOMEBREW == 'true' && env.PRE_RELEASE != 'true' }} + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} - - name: Delete original request tag from repository + - name: Setup Git author information run: | set -ue - git push --delete origin ${SOURCE_TAG} - if: ${{ always() }} + git config --global user.email 'ci@argoproj.com' + git config --global user.name 'CI' + + - name: Check if tag is the latest version and not a pre-release + run: | + set -xue + # Fetch all tag information + git fetch --prune --tags --force + + LATEST_TAG=$(git -c 'versionsort.suffix=-rc' tag --list --sort=version:refname | tail -n1) + + PRE_RELEASE=false + # Check if latest tag is a pre-release + if echo $LATEST_TAG | grep -E -- '-rc[0-9]+$';then + PRE_RELEASE=true + fi + + # Ensure latest tag matches github.ref_name & not a pre-release + if [[ $LATEST_TAG == ${{ github.ref_name }} ]] && [[ $PRE_RELEASE != 'true' ]];then + echo "TAG_STABLE=true" >> $GITHUB_ENV + else + echo "TAG_STABLE=false" >> $GITHUB_ENV + fi + + - name: Update stable tag to latest version + run: | + git tag -f stable ${{ github.ref_name }} + git push -f origin stable + if: ${{ env.TAG_STABLE == 'true' }} + + - name: Check to see if VERSION should be updated on master branch + run: | + 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 + fi + + - 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 + uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # v5.0.2 + with: + commit-message: Bump version in master + title: "chore: Bump version in master" + body: All images built from master should indicate which version we are on track for. + signoff: true + branch: update-version + branch-suffix: random + base: master + if: ${{ env.UPDATE_VERSION == 'true' }} diff --git a/.github/workflows/scorecard.yaml b/.github/workflows/scorecard.yaml new file mode 100644 index 0000000000000..ec3151949541d --- /dev/null +++ b/.github/workflows/scorecard.yaml @@ -0,0 +1,67 @@ +name: Scorecards supply-chain security +on: + # Only the default branch is supported. + branch_protection_rule: + schedule: + - cron: "39 9 * * 2" + push: + branches: ["master"] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecards analysis + runs-on: ubuntu-22.04 + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Used to receive a badge. (Upcoming feature) + id-token: write + # Needs for private repositories. + contents: read + actions: read + if: github.repository == 'argoproj/argo-cd' + + steps: + - name: "Checkout code" + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 + with: + results_file: results.sarif + results_format: sarif + # (Optional) Read-only PAT token. Uncomment the `repo_token` line below if: + # - you want to enable the Branch-Protection check on a *public* repository, or + # - you are installing Scorecards on a *private* repository + # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. + # repo_token: ${{ secrets.SCORECARD_READ_TOKEN }} + + # Publish the results for public repositories to enable scorecard badges. For more details, see + # https://github.com/ossf/scorecard-action#publishing-results. + # For private repositories, `publish_results` will automatically be set to `false`, regardless + # of the value entered here. + publish_results: true + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + # Upload the results to GitHub's code scanning dashboard. + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@83a02f7883b12e0e4e1a146174f5e2292a01e601 # v2.16.4 + with: + sarif_file: results.sarif diff --git a/.github/workflows/update-snyk.yaml b/.github/workflows/update-snyk.yaml index 2e7d68345f2b1..b4d98134e84ad 100644 --- a/.github/workflows/update-snyk.yaml +++ b/.github/workflows/update-snyk.yaml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout code - uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0 + uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} - name: Build reports diff --git a/.gitignore b/.gitignore index 869bb876f8110..ab17deb0db139 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ node_modules/ .kube/ ./test/cmp/*.sock .envrc.remote +.*.swp # ignore built binaries cmd/argocd/argocd diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile index 0560d5987f427..d105f49fde2b1 100644 --- a/.gitpod.Dockerfile +++ b/.gitpod.Dockerfile @@ -1,4 +1,4 @@ -FROM gitpod/workspace-full +FROM gitpod/workspace-full@sha256:511cecde4dc129ca9eb4cc4c479d61f95e5485ebe320a07f5b902f11899956a3 USER root @@ -13,6 +13,8 @@ ENV GOCACHE=/go-build-cache RUN apt-get install redis-server -y RUN go install github.com/mattn/goreman@latest +RUN chown -R gitpod:gitpod /go-build-cache + USER gitpod ENV ARGOCD_REDIS_LOCAL=true diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 0000000000000..26341aa1d80c1 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,121 @@ +project_name: argocd + +before: + hooks: + - go mod download + - make build-ui + +builds: + - id: argocd-cli + main: ./cmd + binary: argocd-{{ .Os}}-{{ .Arch}} + env: + - CGO_ENABLED=0 + flags: + - -v + ldflags: + - -X github.com/argoproj/argo-cd/v2/common.version={{ .Version }} + - -X github.com/argoproj/argo-cd/v2/common.buildDate={{ .Date }} + - -X github.com/argoproj/argo-cd/v2/common.gitCommit={{ .FullCommit }} + - -X github.com/argoproj/argo-cd/v2/common.gitTreeState={{ .Env.GIT_TREE_STATE }} + - -X github.com/argoproj/argo-cd/v2/common.kubectlVersion={{ .Env.KUBECTL_VERSION }} + - -extldflags="-static" + goos: + - linux + - darwin + - windows + goarch: + - amd64 + - arm64 + - s390x + - ppc64le + ignore: + - goos: darwin + goarch: s390x + - goos: darwin + goarch: ppc64le + - goos: windows + goarch: s390x + - goos: windows + goarch: ppc64le + - goos: windows + goarch: arm64 + +archives: + - id: argocd-archive + builds: + - argocd-cli + name_template: |- + {{ .ProjectName }}-{{ .Os }}-{{ .Arch }} + format: binary + +checksum: + name_template: 'cli_checksums.txt' + algorithm: sha256 + +release: + prerelease: auto + draft: false + header: | + ## Quick Start + + ### Non-HA: + + ```shell + kubectl create namespace argocd + kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/{{.Tag}}/manifests/install.yaml + ``` + + ### HA: + + ```shell + kubectl create namespace argocd + kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/{{.Tag}}/manifests/ha/install.yaml + ``` + + ## Release Signatures and Provenance + + All Argo CD container images are signed by cosign. A Provenance is generated for container images and CLI binaries which meet the SLSA Level 3 specifications. See the [documentation](https://argo-cd.readthedocs.io/en/stable/operator-manual/signed-release-assets) on how to verify. + + + ## Upgrading + + If upgrading from a different minor version, be sure to read the [upgrading](https://argo-cd.readthedocs.io/en/stable/operator-manual/upgrading/overview/) documentation. + footer: | + **Full Changelog**: https://github.com/argoproj/argo-cd/compare/{{ .PreviousTag }}...{{ .Tag }} + + + + +snapshot: #### To be removed for PR + name_template: "2.6.0" + +changelog: + use: + github + sort: asc + abbrev: 0 + groups: # Regex use RE2 syntax as defined here: https://github.com/google/re2/wiki/Syntax. + - title: 'Features' + regexp: '^.*?feat(\([[:word:]]+\))??!?:.+$' + order: 100 + - title: 'Bug fixes' + regexp: '^.*?fix(\([[:word:]]+\))??!?:.+$' + order: 200 + - title: 'Documentation' + regexp: '^.*?docs(\([[:word:]]+\))??!?:.+$' + order: 300 + - title: 'Dependency updates' + regexp: '^.*?(feat|fix|chore)\(deps?.+\)!?:.+$' + order: 400 + - title: 'Other work' + order: 999 + filters: + exclude: + - '^test:' + - '^.*?Bump(\([[:word:]]+\))?.+$' + - '^.*?[Bot](\([[:word:]]+\))?.+$' + + +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json + diff --git a/.readthedocs.yml b/.readthedocs.yml index 7b50ab9415bd7..3d69498d27c09 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -4,4 +4,8 @@ mkdocs: fail_on_warning: false python: install: - - requirements: docs/requirements.txt \ No newline at end of file + - requirements: docs/requirements.txt +build: + os: "ubuntu-22.04" + tools: + python: "3.7" diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000000000..83bb38871d96d --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,12 @@ +# All +** @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 +/.goreleaser.yaml @argoproj/argocd-approvers @argoproj/argocd-approvers-ci diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000000..0cef196dca5a1 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1 @@ +Please refer to [the Contribution Guide](https://argo-cd.readthedocs.io/en/latest/developer-guide/code-contributions/) diff --git a/Dockerfile b/Dockerfile index 3a434bc3bbda2..a73da0be1f067 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ -ARG BASE_IMAGE=docker.io/library/ubuntu:22.04 +ARG BASE_IMAGE=docker.io/library/ubuntu:22.04@sha256:0bced47fffa3361afa981854fcabcd4577cd43cebbb808cea2b1f33a3dd7f508 #################################################################################################### # Builder image # Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image # Also used as the image in CI jobs so needs all dependencies #################################################################################################### -FROM docker.io/library/golang:1.18 AS builder +FROM docker.io/library/golang:1.21.8@sha256:856073656d1a517517792e6cdd2f7a5ef080d3ca2dff33e518c8412f140fdd2d AS builder RUN echo 'deb http://deb.debian.org/debian buster-backports main' >> /etc/apt/sources.list @@ -28,7 +28,7 @@ WORKDIR /tmp COPY hack/install.sh hack/tool-versions.sh ./ COPY hack/installers installers -RUN ./install.sh helm-linux && \ +RUN ./install.sh helm && \ INSTALL_PATH=/usr/local/bin ./install.sh kustomize #################################################################################################### @@ -36,6 +36,8 @@ RUN ./install.sh helm-linux && \ #################################################################################################### FROM $BASE_IMAGE AS argocd-base +LABEL org.opencontainers.image.source="https://github.com/argoproj/argo-cd" + USER root ENV ARGOCD_USER_ID=999 @@ -49,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/* @@ -81,7 +83,7 @@ WORKDIR /home/argocd #################################################################################################### # Argo CD UI stage #################################################################################################### -FROM --platform=$BUILDPLATFORM docker.io/library/node:12.18.4 AS argocd-ui +FROM --platform=$BUILDPLATFORM docker.io/library/node:21.6.2@sha256:65998e325b06014d4f1417a8a6afb1540d1ac66521cca76f2221a6953947f9ee AS argocd-ui WORKDIR /src COPY ["ui/package.json", "ui/yarn.lock", "./"] @@ -99,7 +101,7 @@ RUN HOST_ARCH=$TARGETARCH NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OP #################################################################################################### # Argo CD Build stage which performs the actual build of Argo CD binaries #################################################################################################### -FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.18 AS argocd-build +FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.21.3@sha256:02d7116222536a5cf0fcf631f90b507758b669648e0f20186d2dc94a9b419a9b AS argocd-build WORKDIR /go/src/github.com/argoproj/argo-cd @@ -111,7 +113,18 @@ COPY . . COPY --from=argocd-ui /src/dist/app /go/src/github.com/argoproj/argo-cd/ui/dist/app ARG TARGETOS ARG TARGETARCH -RUN GOOS=$TARGETOS GOARCH=$TARGETARCH make argocd-all +# These build args are optional; if not specified the defaults will be taken from the Makefile +ARG GIT_TAG +ARG BUILD_DATE +ARG GIT_TREE_STATE +ARG GIT_COMMIT +RUN GIT_COMMIT=$GIT_COMMIT \ + GIT_TREE_STATE=$GIT_TREE_STATE \ + GIT_TAG=$GIT_TAG \ + BUILD_DATE=$BUILD_DATE \ + GOOS=$TARGETOS \ + GOARCH=$TARGETARCH \ + make argocd-all #################################################################################################### # Final image @@ -130,3 +143,4 @@ RUN ln -s /usr/local/bin/argocd /usr/local/bin/argocd-server && \ ln -s /usr/local/bin/argocd /usr/local/bin/argocd-k8s-auth USER $ARGOCD_USER_ID +ENTRYPOINT ["/usr/bin/tini", "--"] diff --git a/Makefile b/Makefile index 37edfbd618021..96275f9bff76e 100644 --- a/Makefile +++ b/Makefile @@ -3,31 +3,41 @@ CURRENT_DIR=$(shell pwd) DIST_DIR=${CURRENT_DIR}/dist CLI_NAME=argocd BIN_NAME=argocd +CGO_FLAG=0 GEN_RESOURCES_CLI_NAME=argocd-resources-gen HOST_OS:=$(shell go env GOOS) HOST_ARCH:=$(shell go env GOARCH) +TARGET_ARCH?=linux/amd64 + VERSION=$(shell cat ${CURRENT_DIR}/VERSION) -BUILD_DATE=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ') -GIT_COMMIT=$(shell git rev-parse HEAD) -GIT_TAG=$(shell if [ -z "`git status --porcelain`" ]; then git describe --exact-match --tags HEAD 2>/dev/null; fi) -GIT_TREE_STATE=$(shell if [ -z "`git status --porcelain`" ]; then echo "clean" ; else echo "dirty"; fi) +BUILD_DATE:=$(if $(BUILD_DATE),$(BUILD_DATE),$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')) +GIT_COMMIT:=$(if $(GIT_COMMIT),$(GIT_COMMIT),$(shell git rev-parse HEAD)) +GIT_TAG:=$(if $(GIT_TAG),$(GIT_TAG),$(shell if [ -z "`git status --porcelain`" ]; then git describe --exact-match --tags HEAD 2>/dev/null; fi)) +GIT_TREE_STATE:=$(if $(GIT_TREE_STATE),$(GIT_TREE_STATE),$(shell if [ -z "`git status --porcelain`" ]; then echo "clean" ; else echo "dirty"; fi)) VOLUME_MOUNT=$(shell if test "$(go env GOOS)" = "darwin"; then echo ":delegated"; elif test selinuxenabled; then echo ":delegated"; else echo ""; fi) KUBECTL_VERSION=$(shell go list -m k8s.io/client-go | head -n 1 | rev | cut -d' ' -f1 | rev) GOPATH?=$(shell if test -x `which go`; then go env GOPATH; else echo "$(HOME)/go"; fi) GOCACHE?=$(HOME)/.cache/go-build +# Docker command to use +DOCKER?=docker +ifeq ($(DOCKER),podman) +PODMAN_ARGS=--userns keep-id +else +PODMAN_ARGS= +endif + DOCKER_SRCDIR?=$(GOPATH)/src DOCKER_WORKDIR?=/go/src/github.com/argoproj/argo-cd ARGOCD_PROCFILE?=Procfile -# Strict mode has been disabled in latest versions of mkdocs-material. -# Thus pointing to the older image of mkdocs-material matching the version used by argo-cd. -MKDOCS_DOCKER_IMAGE?=squidfunk/mkdocs-material:4.1.1 +# pointing to python 3.7 to match https://github.com/argoproj/argo-cd/blob/master/.readthedocs.yml +MKDOCS_DOCKER_IMAGE?=python:3.7-alpine MKDOCS_RUN_ARGS?= # Configuration for building argocd-test-tools image @@ -47,7 +57,7 @@ ARGOCD_E2E_DEX_PORT?=5556 ARGOCD_E2E_YARN_HOST?=localhost ARGOCD_E2E_DISABLE_AUTH?= -ARGOCD_E2E_TEST_TIMEOUT?=45m +ARGOCD_E2E_TEST_TIMEOUT?=90m ARGOCD_IN_CI?=false ARGOCD_TEST_E2E?=true @@ -74,7 +84,7 @@ SUDO?= # Runs any command in the argocd-test-utils container in server mode # Server mode container will start with uid 0 and drop privileges during runtime define run-in-test-server - $(SUDO) docker run --rm -it \ + $(SUDO) $(DOCKER) run --rm -it \ --name argocd-test-server \ -u $(CONTAINER_UID):$(CONTAINER_GID) \ -e USER_ID=$(CONTAINER_UID) \ @@ -99,13 +109,14 @@ define run-in-test-server -p ${ARGOCD_E2E_APISERVER_PORT}:8080 \ -p 4000:4000 \ -p 5000:5000 \ + $(PODMAN_ARGS) \ $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE):$(TEST_TOOLS_TAG) \ bash -c "$(1)" endef # Runs any command in the argocd-test-utils container in client mode define run-in-test-client - $(SUDO) docker run --rm -it \ + $(SUDO) $(DOCKER) run --rm -it \ --name argocd-test-client \ -u $(CONTAINER_UID):$(CONTAINER_GID) \ -e HOME=/home/user \ @@ -120,13 +131,14 @@ define run-in-test-client -v ${HOME}/.kube:/home/user/.kube${VOLUME_MOUNT} \ -v /tmp:/tmp${VOLUME_MOUNT} \ -w ${DOCKER_WORKDIR} \ + $(PODMAN_ARGS) \ $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE):$(TEST_TOOLS_TAG) \ bash -c "$(1)" endef # define exec-in-test-server - $(SUDO) docker exec -it -u $(CONTAINER_UID):$(CONTAINER_GID) -e ARGOCD_E2E_RECORD=$(ARGOCD_E2E_RECORD) -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) argocd-test-server $(1) + $(SUDO) $(DOCKER) exec -it -u $(CONTAINER_UID):$(CONTAINER_GID) -e ARGOCD_E2E_RECORD=$(ARGOCD_E2E_RECORD) -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) argocd-test-server $(1) endef PATH:=$(PATH):$(PWD)/hack @@ -146,7 +158,8 @@ override LDFLAGS += \ -X ${PACKAGE}.buildDate=${BUILD_DATE} \ -X ${PACKAGE}.gitCommit=${GIT_COMMIT} \ -X ${PACKAGE}.gitTreeState=${GIT_TREE_STATE}\ - -X ${PACKAGE}.kubectlVersion=${KUBECTL_VERSION} + -X ${PACKAGE}.kubectlVersion=${KUBECTL_VERSION}\ + -X "${PACKAGE}.extraBuildInfo=${EXTRA_BUILD_INFO}" ifeq (${STATIC_BUILD}, true) override LDFLAGS += -extldflags "-static" @@ -172,29 +185,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 @@ -209,19 +214,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 notification-docs notification-catalog gogen protogen clientgen openapigen clidocsgen manifests-local +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) @@ -232,11 +240,11 @@ cli: test-tools-image .PHONY: cli-local cli-local: clean-debug - CGO_ENABLED=0 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${CLI_NAME} ./cmd + CGO_ENABLED=${CGO_FLAG} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${CLI_NAME} ./cmd .PHONY: gen-resources-cli-local gen-resources-cli-local: clean-debug - CGO_ENABLED=0 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${GEN_RESOURCES_CLI_NAME} ./hack/gen-resources/cmd + CGO_ENABLED=${CGO_FLAG} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${GEN_RESOURCES_CLI_NAME} ./hack/gen-resources/cmd .PHONY: release-cli release-cli: clean-debug build-ui @@ -251,8 +259,8 @@ release-cli: clean-debug build-ui .PHONY: test-tools-image test-tools-image: ifndef SKIP_TEST_TOOLS_IMAGE - $(SUDO) docker build --build-arg UID=$(CONTAINER_UID) -t $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE) -f test/container/Dockerfile . - $(SUDO) docker tag $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE) $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE):$(TEST_TOOLS_TAG) + $(SUDO) $(DOCKER) build --build-arg UID=$(CONTAINER_UID) -t $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE) -f test/container/Dockerfile . + $(SUDO) $(DOCKER) tag $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE) $(TEST_TOOLS_PREFIX)$(TEST_TOOLS_IMAGE):$(TEST_TOOLS_TAG) endif .PHONY: manifests-local @@ -266,25 +274,25 @@ manifests: test-tools-image # consolidated binary for cli, util, server, repo-server, controller .PHONY: argocd-all argocd-all: clean-debug - CGO_ENABLED=0 GOOS=${GOOS} GOARCH=${GOARCH} go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${BIN_NAME} ./cmd + CGO_ENABLED=${CGO_FLAG} GOOS=${GOOS} GOARCH=${GOARCH} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/${BIN_NAME} ./cmd .PHONY: server server: clean-debug - CGO_ENABLED=0 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-server ./cmd + CGO_ENABLED=${CGO_FLAG} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-server ./cmd .PHONY: repo-server repo-server: - CGO_ENABLED=0 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-repo-server ./cmd + CGO_ENABLED=${CGO_FLAG} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-repo-server ./cmd .PHONY: controller controller: - CGO_ENABLED=0 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-application-controller ./cmd + CGO_ENABLED=${CGO_FLAG} GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-application-controller ./cmd .PHONY: build-ui build-ui: - DOCKER_BUILDKIT=1 docker build -t argocd-ui --target argocd-ui . + DOCKER_BUILDKIT=1 $(DOCKER) build -t argocd-ui --platform=$(TARGET_ARCH) --target argocd-ui . find ./ui/dist -type f -not -name gitkeep -delete - docker run -v ${CURRENT_DIR}/ui/dist/app:/tmp/app --rm -t argocd-ui sh -c 'cp -r ./dist/app/* /tmp/app/' + $(DOCKER) run -v ${CURRENT_DIR}/ui/dist/app:/tmp/app --rm -t argocd-ui sh -c 'cp -r ./dist/app/* /tmp/app/' .PHONY: image ifeq ($(DEV_IMAGE), true) @@ -293,29 +301,29 @@ ifeq ($(DEV_IMAGE), true) # the dist directory is under .dockerignore. IMAGE_TAG="dev-$(shell git describe --always --dirty)" image: build-ui - DOCKER_BUILDKIT=1 docker build --platform=linux/amd64 -t argocd-base --target argocd-base . - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd ./cmd + DOCKER_BUILDKIT=1 $(DOCKER) build --platform=$(TARGET_ARCH) -t argocd-base --target argocd-base . + CGO_ENABLED=${CGO_FLAG} GOOS=linux GOARCH=amd64 GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd ./cmd ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-server ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-application-controller ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-repo-server ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-cmp-server ln -sfn ${DIST_DIR}/argocd ${DIST_DIR}/argocd-dex cp Dockerfile.dev dist - DOCKER_BUILDKIT=1 docker build --platform=linux/amd64 -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) -f dist/Dockerfile.dev dist + DOCKER_BUILDKIT=1 $(DOCKER) build --platform=$(TARGET_ARCH) -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) -f dist/Dockerfile.dev dist else image: - DOCKER_BUILDKIT=1 docker build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) . + DOCKER_BUILDKIT=1 $(DOCKER) build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) --platform=$(TARGET_ARCH) . endif - @if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) ; fi + @if [ "$(DOCKER_PUSH)" = "true" ] ; then $(DOCKER) push $(IMAGE_PREFIX)argocd:$(IMAGE_TAG) ; fi .PHONY: armimage armimage: - docker build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG)-arm . + $(DOCKER) build -t $(IMAGE_PREFIX)argocd:$(IMAGE_TAG)-arm . .PHONY: builder-image builder-image: - docker build -t $(IMAGE_PREFIX)argo-cd-ci-builder:$(IMAGE_TAG) --target builder . - @if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argo-cd-ci-builder:$(IMAGE_TAG) ; fi + $(DOCKER) build -t $(IMAGE_PREFIX)argo-cd-ci-builder:$(IMAGE_TAG) --target builder . + @if [ "$(DOCKER_PUSH)" = "true" ] ; then $(DOCKER) push $(IMAGE_PREFIX)argo-cd-ci-builder:$(IMAGE_TAG) ; fi .PHONY: mod-download mod-download: test-tools-image @@ -333,7 +341,7 @@ mod-vendor: test-tools-image mod-vendor-local: mod-download-local go mod vendor -# Deprecated - replace by install-local-tools +# Deprecated - replace by install-tools-local .PHONY: install-lint-tools install-lint-tools: ./hack/install.sh lint-tools @@ -349,7 +357,7 @@ lint-local: golangci-lint --version # NOTE: If you get a "Killed" OOM message, try reducing the value of GOGC # See https://github.com/golangci/golangci-lint#memory-usage-of-golangci-lint - GOGC=$(ARGOCD_LINT_GOGC) GOMAXPROCS=2 golangci-lint run --fix --verbose --timeout 3000s + GOGC=$(ARGOCD_LINT_GOGC) GOMAXPROCS=2 golangci-lint run --enable gofmt --fix --verbose --timeout 3000s --max-issues-per-linter 0 --max-same-issues 0 .PHONY: lint-ui lint-ui: test-tools-image @@ -368,7 +376,7 @@ build: test-tools-image # Build all Go code (local version) .PHONY: build-local build-local: - go build -v `go list ./... | grep -v 'resource_customizations\|test/e2e'` + GODEBUG="tarinsecurepath=0,zipinsecurepath=0" go build -v `go list ./... | grep -v 'resource_customizations\|test/e2e'` # Run all unit tests # @@ -383,9 +391,9 @@ test: test-tools-image .PHONY: test-local test-local: if test "$(TEST_MODULE)" = ""; then \ - ./hack/test.sh -coverprofile=coverage.out `go list ./... | grep -v 'test/e2e'`; \ + DIST_DIR=${DIST_DIR} RERUN_FAILS=0 PACKAGES=`go list ./... | grep -v 'test/e2e'` ./hack/test.sh -coverprofile=coverage.out; \ else \ - ./hack/test.sh -coverprofile=coverage.out "$(TEST_MODULE)"; \ + DIST_DIR=${DIST_DIR} RERUN_FAILS=0 PACKAGES="$(TEST_MODULE)" ./hack/test.sh -coverprofile=coverage.out "$(TEST_MODULE)"; \ fi .PHONY: test-race @@ -397,9 +405,9 @@ test-race: test-tools-image .PHONY: test-race-local test-race-local: if test "$(TEST_MODULE)" = ""; then \ - ./hack/test.sh -race -coverprofile=coverage.out `go list ./... | grep -v 'test/e2e'`; \ + DIST_DIR=${DIST_DIR} RERUN_FAILS=0 PACKAGES=`go list ./... | grep -v 'test/e2e'` ./hack/test.sh -race -coverprofile=coverage.out; \ else \ - ./hack/test.sh -race -coverprofile=coverage.out "$(TEST_MODULE)"; \ + DIST_DIR=${DIST_DIR} RERUN_FAILS=0 PACKAGES="$(TEST_MODULE)" ./hack/test.sh -race -coverprofile=coverage.out; \ fi # Run the E2E test suite. E2E test servers (see start-e2e target) must be @@ -413,7 +421,7 @@ test-e2e: test-e2e-local: cli-local # NO_PROXY ensures all tests don't go out through a proxy if one is configured on the test system export GO111MODULE=off - ARGOCD_E2E_RECORD=${ARGOCD_E2E_RECORD} ARGOCD_GPG_ENABLED=true NO_PROXY=* ./hack/test.sh -timeout $(ARGOCD_E2E_TEST_TIMEOUT) -v ./test/e2e + DIST_DIR=${DIST_DIR} RERUN_FAILS=5 PACKAGES="./test/e2e" ARGOCD_E2E_RECORD=${ARGOCD_E2E_RECORD} ARGOCD_GPG_ENABLED=true NO_PROXY=* ./hack/test.sh -timeout $(ARGOCD_E2E_TEST_TIMEOUT) -v # Spawns a shell in the test server container for debugging purposes debug-test-server: test-tools-image @@ -426,7 +434,7 @@ debug-test-client: test-tools-image # Starts e2e server in a container .PHONY: start-e2e start-e2e: test-tools-image - docker version + $(DOCKER) version mkdir -p ${GOCACHE} $(call run-in-test-server,make ARGOCD_PROCFILE=test/container/Procfile start-e2e-local) @@ -435,6 +443,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 @@ -455,7 +464,9 @@ 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_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} @@ -470,7 +481,7 @@ clean: clean-debug .PHONY: start start: test-tools-image - docker version + $(DOCKER) version $(call run-in-test-server,make ARGOCD_PROCFILE=test/container/Procfile start-local ARGOCD_START=${ARGOCD_START}) # Starts a local instance of ArgoCD @@ -486,6 +497,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} @@ -519,7 +531,7 @@ build-docs-local: .PHONY: build-docs build-docs: - docker run ${MKDOCS_RUN_ARGS} --rm -it -v ${CURRENT_DIR}:/docs --entrypoint "" ${MKDOCS_DOCKER_IMAGE} sh -c 'pip install -r docs/requirements.txt; mkdocs build' + $(DOCKER) run ${MKDOCS_RUN_ARGS} --rm -it -v ${CURRENT_DIR}:/docs -w /docs --entrypoint "" ${MKDOCS_DOCKER_IMAGE} sh -c 'pip install -r docs/requirements.txt; mkdocs build' .PHONY: serve-docs-local serve-docs-local: @@ -527,8 +539,7 @@ serve-docs-local: .PHONY: serve-docs serve-docs: - docker run ${MKDOCS_RUN_ARGS} --rm -it -p 8000:8000 -v ${CURRENT_DIR}/site:/site -w /site --entrypoint "" ${MKDOCS_DOCKER_IMAGE} python3 -m http.server --bind 0.0.0.0 8000 - + $(DOCKER) run ${MKDOCS_RUN_ARGS} --rm -it -p 8000:8000 -v ${CURRENT_DIR}:/docs -w /docs --entrypoint "" ${MKDOCS_DOCKER_IMAGE} sh -c 'pip install -r docs/requirements.txt; mkdocs serve -a $$(ip route get 1 | awk '\''{print $$7}'\''):8000' # Verify that kubectl can connect to your K8s cluster from Docker .PHONY: verify-kube-connect @@ -551,7 +562,8 @@ install-tools-local: install-test-tools-local install-codegen-tools-local instal .PHONY: install-test-tools-local install-test-tools-local: ./hack/install.sh kustomize - ./hack/install.sh helm-linux + ./hack/install.sh helm + ./hack/install.sh gotestsum # Installs all tools required for running codegen (Linux packages) .PHONY: install-codegen-tools-local @@ -579,7 +591,7 @@ list: .PHONY: applicationset-controller applicationset-controller: - CGO_ENABLED=0 go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-applicationset-controller ./cmd + GODEBUG="tarinsecurepath=0,zipinsecurepath=0" CGO_ENABLED=${CGO_FLAG} go build -v -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-applicationset-controller ./cmd .PHONY: checksums checksums: @@ -596,3 +608,55 @@ snyk-non-container-tests: .PHONY: snyk-report snyk-report: ./hack/snyk-report.sh $(target_branch) + +.PHONY: help +help: + @echo 'Note: Generally an item w/ (-local) will run inside docker unless you use the -local variant' + @echo + @echo 'Common targets' + @echo + @echo 'all -- make cli and image' + @echo + @echo 'components:' + @echo ' applicationset-controller -- applicationset controller' + @echo ' cli(-local) -- argocd cli program' + @echo ' controller -- controller (orchestrator)' + @echo ' repo-server -- repo server (manage repository instances)' + @echo ' server -- argocd web application' + @echo + @echo 'build:' + @echo ' image -- make image of the following items' + @echo ' build(-local) -- compile go' + @echo ' build-docs(-local) -- build docs' + @echo ' build-ui -- compile typescript' + @echo + @echo 'run:' + @echo ' run -- run the components locally' + @echo ' serve-docs(-local) -- expose the documents for viewing in a browser' + @echo + @echo 'release:' + @echo ' release-cli' + @echo ' release-precheck' + @echo ' checksums' + @echo + @echo 'docs:' + @echo ' build-docs(-local)' + @echo ' serve-docs(-local)' + @echo ' notification-docs' + @echo ' clidocsgen' + @echo + @echo 'testing:' + @echo ' test(-local)' + @echo ' start-e2e(-local)' + @echo ' test-e2e(-local)' + @echo ' test-race(-local)' + @echo + @echo 'debug:' + @echo ' list -- list all make targets' + @echo ' install-tools-local -- install all the tools below' + @echo ' install-lint-tools(-local)' + @echo + @echo 'codegen:' + @echo ' codegen(-local) -- if using -local, run the following targets first' + @echo ' install-codegen-tools-local -- run this to install the codegen tools' + @echo ' install-go-tools-local -- run this to install go libraries for codegen' diff --git a/OWNERS b/OWNERS index 2dc34bf6fc359..56e037e282a0a 100644 --- a/OWNERS +++ b/OWNERS @@ -5,6 +5,7 @@ owners: approvers: - alexec - alexmt +- gdsoumya - jannfis - jessesuen - jgwest @@ -29,3 +30,4 @@ reviewers: - saumeya - zachaller - 34fathombelow +- alexef diff --git a/Procfile b/Procfile index 56c9440177bfc..4862b0230062f 100644 --- a/Procfile +++ b/Procfile @@ -1,12 +1,13 @@ -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:-''}" -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 && 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} redis:$(grep "image: redis" manifests/base/redis/argocd-redis-deployment.yaml | cut -d':' -f3) --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; fi" -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_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-repo-server ARGOCD_GPG_ENABLED=${ARGOCD_GPG_ENABLED:-false} $COMMAND --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --otlp-address=${ARGOCD_OTLP_ADDRESS}" -cmp-server: [ "$ARGOCD_E2E_TEST" == 'true' ] && exit 0 || [ "$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-cmp-server ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} $COMMAND --config-dir-path ./test/cmp --loglevel debug --otlp-address=${ARGOCD_OTLP_ADDRESS}" +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" +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_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-repo-server ARGOCD_GPG_ENABLED=${ARGOCD_GPG_ENABLED:-false} $COMMAND --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --otlp-address=${ARGOCD_OTLP_ADDRESS}" +cmp-server: [ "$ARGOCD_E2E_TEST" = 'true' ] && exit 0 || [ "$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-cmp-server ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} $COMMAND --config-dir-path ./test/cmp --loglevel debug --otlp-address=${ARGOCD_OTLP_ADDRESS}" ui: sh -c 'cd ui && ${ARGOCD_E2E_YARN_CMD:-yarn} start' 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_ASK_PASS_SOCK=/tmp/applicationset-ask-pass.sock 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" +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 --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 1ed4164fd60ff..707848191c830 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,19 @@ **Releases:** [![Release Version](https://img.shields.io/github/v/release/argoproj/argo-cd?label=argo-cd)](https://github.com/argoproj/argo-cd/releases/latest) [![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/argo-cd)](https://artifacthub.io/packages/helm/argo/argo-cd) +[![SLSA 3](https://slsa.dev/images/gh-badge-level3.svg)](https://slsa.dev) **Code:** [![Integration tests](https://github.com/argoproj/argo-cd/workflows/Integration%20tests/badge.svg?branch=master)](https://github.com/argoproj/argo-cd/actions?query=workflow%3A%22Integration+tests%22) [![codecov](https://codecov.io/gh/argoproj/argo-cd/branch/master/graph/badge.svg)](https://codecov.io/gh/argoproj/argo-cd) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/4486/badge)](https://bestpractices.coreinfrastructure.org/projects/4486) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/argoproj/argo-cd/badge)](https://api.securityscorecards.dev/projects/github.com/argoproj/argo-cd) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fargoproj%2Fargo-cd.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fargoproj%2Fargo-cd?ref=badge_shield) **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 @@ -54,7 +57,7 @@ Participation in the Argo CD project is governed by the [CNCF Code of Conduct](h ### Blogs and Presentations 1. [Awesome-Argo: A Curated List of Awesome Projects and Resources Related to Argo](https://github.com/terrytangyuan/awesome-argo) -1. [Unveil the Secret Ingredients of Continuous Delivery at Enterprise Scale with Argo CD](https://blog.akuity.io/unveil-the-secret-ingredients-of-continuous-delivery-at-enterprise-scale-with-argo-cd-7c5b4057ee49) +1. [Unveil the Secret Ingredients of Continuous Delivery at Enterprise Scale with Argo CD](https://akuity.io/blog/unveil-the-secret-ingredients-of-continuous-delivery-at-enterprise-scale-with-argocd-kubecon-china-2021/) 1. [GitOps Without Pipelines With ArgoCD Image Updater](https://youtu.be/avPUQin9kzU) 1. [Combining Argo CD (GitOps), Crossplane (Control Plane), And KubeVela (OAM)](https://youtu.be/eEcgn_gU3SM) 1. [How to Apply GitOps to Everything - Combining Argo CD and Crossplane](https://youtu.be/yrj4lmScKHQ) @@ -80,7 +83,8 @@ Participation in the Argo CD project is governed by the [CNCF Code of Conduct](h 1. [Applied GitOps with Argo CD](https://thenewstack.io/applied-gitops-with-argocd/) 1. [Solving configuration drift using GitOps with Argo CD](https://www.cncf.io/blog/2020/12/17/solving-configuration-drift-using-gitops-with-argo-cd/) 1. [Decentralized GitOps over environments](https://blogs.sap.com/2021/05/06/decentralized-gitops-over-environments/) -1. [How GitOps and Operators mark the rise of Infrastructure-As-Software](https://paytmlabs.com/blog/2021/10/how-to-improve-operational-work-with-operators-and-gitops/) 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/SECURITY.md b/SECURITY.md index c1f2e92e45c8c..479cd5ef29c97 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,6 +1,6 @@ # Security Policy for Argo CD -Version: **v1.4 (2022-01-23)** +Version: **v1.5 (2023-03-06)** ## Preface @@ -35,13 +35,11 @@ impact on Argo CD before opening an issue at least roughly. ## Supported Versions -We currently support the most recent release (`N`, e.g. `1.8`) and the release -previous to the most recent one (`N-1`, e.g. `1.7`). With the release of -`N+1`, `N-1` drops out of support and `N` becomes `N-1`. +We currently support the last 3 minor versions of Argo CD with security and bug fixes. We regularly perform patch releases (e.g. `1.8.5` and `1.7.12`) for the supported versions, which will contain fixes for security vulnerabilities and -important bugs. Prior releases might receive critical security fixes on a best +important bugs. Prior releases might receive critical security fixes on best effort basis, however, it cannot be guaranteed that security fixes get back-ported to these unsupported versions. @@ -52,7 +50,7 @@ of releasing it within a patch branch for the currently supported releases. ## Reporting a Vulnerability -If you find a security related bug in ArgoCD, we kindly ask you for responsible +If you find a security related bug in Argo CD, we kindly ask you for responsible disclosure and for giving us appropriate time to react, analyze and develop a fix to mitigate the found security vulnerability. @@ -61,13 +59,28 @@ and disclosure with you. Sometimes, it might take a little longer for us to react (e.g. out of office conditions), so please bear with us in these cases. We will publish security advisories using the -[Git Hub Security Advisories](https://github.com/argoproj/argo-cd/security/advisories) -feature to keep our community well informed, and will credit you for your +[GitHub Security Advisories](https://github.com/argoproj/argo-cd/security/advisories) +feature to keep our community well-informed, and will credit you for your findings (unless you prefer to stay anonymous, of course). -Please report vulnerabilities by e-mail to the following address: +There are two ways to report a vulnerability to the Argo CD team: -* cncf-argo-security@lists.cncf.io +* By opening a draft GitHub security advisory: https://github.com/argoproj/argo-cd/security/advisories/new +* By e-mail to the following address: cncf-argo-security@lists.cncf.io + +## Internet Bug Bounty collaboration + +We're happy to announce that the Argo project is collaborating with the great +folks over at +[Hacker One](https://hackerone.com/) and their +[Internet Bug Bounty program](https://hackerone.com/ibb) +to reward the awesome people who find security vulnerabilities in the four +main Argo projects (CD, Events, Rollouts and Workflows) and then work with +us to fix and disclose them in a responsible manner. + +If you report a vulnerability to us as outlined in this security policy, we +will work together with you to find out whether your finding is eligible for +claiming a bounty, and also on how to claim it. ## Securing your Argo CD Instance diff --git a/SECURITY_CONTACTS b/SECURITY_CONTACTS index 1d5575609323e..e4651b11531dc 100644 --- a/SECURITY_CONTACTS +++ b/SECURITY_CONTACTS @@ -1,7 +1,7 @@ # Defined below are the security contacts for this repo. # # DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE -# INSTRUCTIONS AT https://argo-cd.readthedocs.io/en/latest/security_considerations/#reporting-vulnerabilities +# INSTRUCTIONS AT https://github.com/argoproj/argo-cd/security/policy alexmt edlee2121 diff --git a/USERS.md b/USERS.md index 426760908b1d2..6f35c32acb661 100644 --- a/USERS.md +++ b/USERS.md @@ -7,22 +7,30 @@ Currently, the following organizations are **officially** using Argo CD: 1. [127Labs](https://127labs.com/) 1. [3Rein](https://www.3rein.com/) +1. [4data](https://4data.ch/) 1. [7shifts](https://www.7shifts.com/) 1. [Adevinta](https://www.adevinta.com/) 1. [Adfinis](https://adfinis.com) 1. [Adventure](https://jp.adventurekk.com/) +1. [Adyen](https://www.adyen.com) 1. [AirQo](https://airqo.net/) 1. [Akuity](https://akuity.io/) +1. [Albert Heijn](https://ah.nl/) 1. [Alibaba Group](https://www.alibabagroup.com/) 1. [Allianz Direct](https://www.allianzdirect.de/) 1. [Amadeus IT Group](https://amadeus.com/) 1. [Ambassador Labs](https://www.getambassador.io/) +1. [Ancestry](https://www.ancestry.com/) 1. [ANSTO - Australian Synchrotron](https://www.synchrotron.org.au/) 1. [Ant Group](https://www.antgroup.com/) 1. [AppDirect](https://www.appdirect.com) 1. [Arctiq Inc.](https://www.arctiq.ca) +2. [Arturia](https://www.arturia.com) 1. [ARZ Allgemeines Rechenzentrum GmbH](https://www.arz.at/) +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) 1. [BCDevExchange DevOps Platform](https://bcdevexchange.org/DevOpsPlatform) 1. [Beat](https://thebeat.co/en/) @@ -31,37 +39,46 @@ Currently, the following organizations are **officially** using Argo CD: 1. [BigPanda](https://bigpanda.io) 1. [BioBox Analytics](https://biobox.io) 1. [BMW Group](https://www.bmwgroup.com/) -1. [PT Boer Technology (Btech)](https://btech.id/) 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) -1. [CARFAX](https://www.carfax.com) 1. [CARFAX Europe](https://www.carfax.eu) +1. [CARFAX](https://www.carfax.com) +1. [Carrefour Group](https://www.carrefour.com) 1. [Casavo](https://casavo.com) 1. [Celonis](https://www.celonis.com/) 1. [CERN](https://home.cern/) +1. [Chainnodes](https://chainnodes.org) 1. [Chargetrip](https://chargetrip.com) 1. [Chime](https://www.chime.com) 1. [Cisco ET&I](https://eti.cisco.com/) +1. [Cloud Posse](https://www.cloudposse.com/) 1. [Cloud Scale](https://cloudscaleinc.com/) +1. [Cloudmate](https://cloudmt.co.kr/) +1. [Cloudogu](https://cloudogu.com/) 1. [Cobalt](https://www.cobalt.io/) 1. [Codefresh](https://www.codefresh.io/) 1. [Codility](https://www.codility.com/) 1. [Commonbond](https://commonbond.co/) 1. [Coralogix](https://coralogix.com/) -1. [CROZ d.o.o.](https://croz.net/) 1. [Crédit Agricole CIB](https://www.ca-cib.com) +1. [CROZ d.o.o.](https://croz.net/) 1. [CyberAgent](https://www.cyberagent.co.jp/en/) 1. [Cybozu](https://cybozu-global.com) 1. [D2iQ](https://www.d2iq.com) +1. [DaoCloud](https://daocloud.io/) 1. [Datarisk](https://www.datarisk.io/) 1. [Deloitte](https://www.deloitte.com/) 1. [Deutsche Telekom AG](https://telekom.com) 1. [Devopsi - Poland Software/DevOps Consulting](https://devopsi.pl/) 1. [Devtron Labs](https://github.com/devtron-labs/devtron) +1. [DigitalOcean](https://www.digitalocean.com) 1. [Divistant](https://divistant.com) +1. [Dott](https://ridedott.com) 1. [Doximity](https://www.doximity.com/) 1. [EDF Renewables](https://www.edf-re.com/) 1. [edX](https://edx.org) @@ -73,10 +90,15 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Energisme](https://energisme.com/) 1. [enigmo](https://enigmo.co.jp/) 1. [Envoy](https://envoy.com/) +1. [Factorial](https://factorialhr.com/) +1. [Farfetch](https://www.farfetch.com) 1. [Faro](https://www.faro.com/) 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/) @@ -90,10 +112,14 @@ Currently, the following organizations are **officially** using Argo CD: 1. [gloat](https://gloat.com/) 1. [GLOBIS](https://globis.com) 1. [Glovo](https://www.glovoapp.com) +1. [GlueOps](https://glueops.dev) 1. [GMETRI](https://gmetri.com/) 1. [Gojek](https://www.gojek.io/) +1. [GoTo Financial](https://gotofinancial.com/) +1. [GoTo](https://www.goto.com/) 1. [Greenpass](https://www.greenpass.com.br/) 1. [Gridfuse](https://gridfuse.com/) +1. [Groww](https://groww.in) 1. [Grupo MasMovil](https://grupomasmovil.com/en/) 1. [Handelsbanken](https://www.handelsbanken.se) 1. [Healy](https://www.healyworld.net) @@ -102,33 +128,44 @@ Currently, the following organizations are **officially** using Argo CD: 1. [hipages](https://hipages.com.au/) 1. [Hiya](https://hiya.com) 1. [Honestbank](https://honestbank.com) +1. [Hostinger](https://www.hostinger.com) +1. [IABAI](https://www.iab.ai) 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/) +1. [Info Support](https://www.infosupport.com/) 1. [InsideBoard](https://www.insideboard.com) 1. [Intuit](https://www.intuit.com/) +1. [Jellysmack](https://www.jellysmack.com) 1. [Joblift](https://joblift.com/) 1. [JovianX](https://www.jovianx.com/) 1. [Kaltura](https://corp.kaltura.com/) 1. [Kandji](https://www.kandji.io/) -1. [KarrotPay](https://www.daangnpay.com/) 1. [Karrot](https://www.daangn.com/) +1. [KarrotPay](https://www.daangnpay.com/) 1. [Kasa](https://kasa.co.kr/) 1. [Keeeb](https://www.keeeb.com/) +1. [KelkooGroup](https://www.kelkoogroup.com) 1. [Keptn](https://keptn.sh) 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/) +1. [Kvist](https://kvistsolutions.com) 1. [LexisNexis](https://www.lexisnexis.com/) 1. [Lian Chu Securities](https://lczq.com) 1. [Liatrio](https://www.liatrio.com) 1. [Lightricks](https://www.lightricks.com/) 1. [LINE](https://linecorp.com/en/) +1. [Loom](https://www.loom.com/) +1. [Lucid Motors](https://www.lucidmotors.com/) 1. [Lytt](https://www.lytt.co/) 1. [Magic Leap](https://www.magicleap.com/) 1. [Majid Al Futtaim](https://www.majidalfuttaim.com/) @@ -139,10 +176,13 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Max Kelsen](https://www.maxkelsen.com/) 1. [MeDirect](https://medirect.com.mt/) 1. [Meican](https://meican.com/) +1. [Meilleurs Agents](https://www.meilleursagents.com/) 1. [Mercedes-Benz Tech Innovation](https://www.mercedes-benz-techinnovation.com/) +1. [Mercedes-Benz.io](https://www.mercedes-benz.io/) 1. [Metanet](http://www.metanet.co.kr/en/) 1. [MindSpore](https://mindspore.cn) 1. [Mirantis](https://mirantis.com/) +1. [Mission Lane](https://missionlane.com) 1. [mixi Group](https://mixi.co.jp/) 1. [Moengage](https://www.moengage.com/) 1. [Money Forward](https://corp.moneyforward.com/en/) @@ -151,15 +191,21 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Natura &Co](https://naturaeco.com/) 1. [Nethopper](https://nethopper.io) 1. [New Relic](https://newrelic.com/) +1. [Nextbasket](https://nextbasket.com) 1. [Nextdoor](https://nextdoor.com/) 1. [Nikkei](https://www.nikkei.co.jp/nikkeiinfo/en/) 1. [Nitro](https://gonitro.com) +1. [NYCU, CS IT Center](https://it.cs.nycu.edu.tw) 1. [Objective](https://www.objective.com.br/) 1. [OCCMundial](https://occ.com.mx) 1. [Octadesk](https://octadesk.com) +1. [Olfeo](https://www.olfeo.com/) 1. [omegaUp](https://omegaUp.com) +1. [Omni](https://omni.se/) +1. [Oncourse Home Solutions](https://oncoursehome.com/) 1. [openEuler](https://openeuler.org) 1. [openGauss](https://opengauss.org/) +1. [OpenGov](https://opengov.com) 1. [openLooKeng](https://openlookeng.io) 1. [OpenSaaS Studio](https://opensaas.studio) 1. [Opensurvey](https://www.opensurvey.co.kr/) @@ -167,42 +213,64 @@ Currently, the following organizations are **officially** using Argo CD: 1. [OpsVerse](https://opsverse.io) 1. [Optoro](https://www.optoro.com/) 1. [Orbital Insight](https://orbitalinsight.com/) +1. [Oscar Health Insurance](https://hioscar.com/) 1. [p3r](https://www.p3r.one/) 1. [Packlink](https://www.packlink.com/) -1. [Pandosearch](https://www.pandosearch.com/en/home) 1. [PagerDuty](https://www.pagerduty.com/) +1. [Pandosearch](https://www.pandosearch.com/en/home) 1. [Patreon](https://www.patreon.com/) +1. [PayIt](https://payitgov.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) 1. [Preferred Networks](https://preferred.jp/en/) +1. [Previder BV](https://previder.nl) +1. [Procore](https://www.procore.com) 1. [Productboard](https://www.productboard.com/) 1. [Prudential](https://prudential.com.sg) +1. [PT Boer Technology (Btech)](https://btech.id/) 1. [PUBG](https://www.pubg.com) +1. [Puzzle ITC](https://www.puzzle.ch/) 1. [Qonto](https://qonto.com) 1. [QuintoAndar](https://quintoandar.com.br) 1. [Quipper](https://www.quipper.com/) 1. [RapidAPI](https://www.rapidapi.com/) 1. [Recreation.gov](https://www.recreation.gov/) 1. [Red Hat](https://www.redhat.com/) +1. [Redpill Linpro](https://www.redpill-linpro.com/) +1. [Reenigne Cloud](https://reenigne.ca) 1. [reev.com](https://www.reev.com/) 1. [RightRev](https://rightrev.com/) +1. [Rijkswaterstaat](https://www.rijkswaterstaat.nl/en) 1. [Rise](https://www.risecard.eu/) 1. [Riskified](https://www.riskified.com/) 1. [Robotinfra](https://www.robotinfra.com) +1. [Rocket.Chat](https://rocket.chat) 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. [Shield](https://shield.com) 1. [SI Analytics](https://si-analytics.ai) 1. [Skit](https://skit.ai/) 1. [Skyscanner](https://www.skyscanner.net/) +1. [Smart Pension](https://www.smartpension.co.uk/) 1. [Smilee.io](https://smilee.io) +1. [Smood.ch](https://www.smood.ch/) 1. [Snapp](https://snapp.ir/) 1. [Snyk](https://snyk.io/) 1. [Softway Medical](https://www.softwaymedical.fr/) @@ -211,6 +279,9 @@ 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. [SternumIOT](https://sternumiot.com) +1. [StreamNative](https://streamnative.io) 1. [Stuart](https://stuart.com/) 1. [Sumo Logic](https://sumologic.com/) 1. [Sutpc](http://www.sutpc.com/) @@ -223,7 +294,9 @@ 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/) 1. [Ticketmaster](https://ticketmaster.com) 1. [Tiger Analytics](https://www.tigeranalytics.com/) @@ -232,14 +305,21 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Trendyol](https://www.trendyol.com/) 1. [tru.ID](https://tru.id) 1. [Trusting Social](https://trustingsocial.com/) +1. [Twilio Segment](https://segment.com/) 1. [Twilio SendGrid](https://sendgrid.com) 1. [tZERO](https://www.tzero.com/) +1. [U.S. Veterans Affairs Department](https://www.va.gov/) 1. [UBIO](https://ub.io/) 1. [UFirstGroup](https://www.ufirstgroup.com/en/) 1. [ungleich.ch](https://ungleich.ch/) 1. [Unifonic Inc](https://www.unifonic.com/) 1. [Universidad Mesoamericana](https://www.umes.edu.gt/) +1. [Upsider Inc.](https://up-sider.com/lp/) +1. [Urbantz](https://urbantz.com/) +1. [Vectra](https://www.vectra.ai) +1. [Veepee](https://www.veepee.com) 1. [Viaduct](https://www.viaduct.ai/) +1. [VietMoney](https://vietmoney.vn/) 1. [Vinted](https://vinted.com/) 1. [Virtuo](https://www.govirtuo.com/) 1. [VISITS Technologies](https://visits.world/en) @@ -260,5 +340,6 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Yieldlab](https://www.yieldlab.de/) 1. [Youverify](https://youverify.co/) 1. [Yubo](https://www.yubo.live/) +1. [ZDF](https://www.zdf.de/) 1. [Zimpler](https://www.zimpler.com/) 1. [ZOZO](https://corp.zozo.com/) diff --git a/VERSION b/VERSION index e70b4523ae7ff..46b81d815a23b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.6.0 +2.11.0 diff --git a/applicationset/controllers/applicationset_controller.go b/applicationset/controllers/applicationset_controller.go index 9afc278b35a6c..e1275e75d3ba2 100644 --- a/applicationset/controllers/applicationset_controller.go +++ b/applicationset/controllers/applicationset_controller.go @@ -17,6 +17,7 @@ package controllers import ( "context" "fmt" + "reflect" "time" log "github.com/sirupsen/logrus" @@ -27,21 +28,30 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/kubernetes" + k8scache "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" + "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/source" "github.com/argoproj/argo-cd/v2/applicationset/generators" "github.com/argoproj/argo-cd/v2/applicationset/utils" "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/util/db" + "github.com/argoproj/argo-cd/v2/util/glob" argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned" argoutil "github.com/argoproj/argo-cd/v2/util/argo" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application" ) const ( @@ -53,7 +63,7 @@ const ( ) var ( - preservedAnnotations = []string{ + defaultPreservedAnnotations = []string{ NotifiedAnnotationKey, argov1alpha1.AnnotationKeyRefresh, } @@ -62,16 +72,22 @@ var ( // ApplicationSetReconciler reconciles a ApplicationSet object type ApplicationSetReconciler struct { client.Client - Scheme *runtime.Scheme - Recorder record.EventRecorder - Generators map[string]generators.Generator - ArgoDB db.ArgoDB - ArgoAppClientset appclientset.Interface - KubeClientset kubernetes.Interface - utils.Policy + Scheme *runtime.Scheme + Recorder record.EventRecorder + Generators map[string]generators.Generator + ArgoDB db.ArgoDB + ArgoAppClientset appclientset.Interface + KubeClientset kubernetes.Interface + Policy argov1alpha1.ApplicationsSyncPolicy + EnablePolicyOverride bool utils.Renderer - - EnableProgressiveRollouts bool + ArgoCDNamespace string + ApplicationSetNamespaces []string + EnableProgressiveSyncs bool + SCMRootCAPath string + GlobalPreservedAnnotations []string + GlobalPreservedLabels []string + Cache cache.Cache } // +kubebuilder:rbac:groups=argoproj.io,resources=applicationsets,verbs=get;list;watch;create;update;patch;delete @@ -92,29 +108,41 @@ 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) - if err != nil { + desiredApplications, applicationSetReason, generatorsErr := r.generateApplications(logCtx, applicationSetInfo) + if generatorsErr != nil { _ = r.setApplicationSetStatusCondition(ctx, &applicationSetInfo, argov1alpha1.ApplicationSetCondition{ Type: argov1alpha1.ApplicationSetConditionErrorOccurred, - Message: err.Error(), + Message: generatorsErr.Error(), Reason: string(applicationSetReason), Status: argov1alpha1.ApplicationSetConditionStatusTrue, }, parametersGenerated, ) - return ctrl.Result{}, err + if len(desiredApplications) < 1 { + return ctrl.Result{}, generatorsErr + } } parametersGenerated = true - validateErrors, err := r.validateGeneratedApplications(ctx, desiredApplications, applicationSetInfo, req.Namespace) + validateErrors, err := r.validateGeneratedApplications(ctx, desiredApplications, applicationSetInfo) if err != nil { // While some generators may return an error that requires user intervention, // other generators reference external resources that may change to cause @@ -142,19 +170,30 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque // appSyncMap tracks which apps will be synced during this reconciliation. appSyncMap := map[string]bool{} - if r.EnableProgressiveRollouts && applicationSetInfo.Spec.Strategy != nil { - applications, err := r.getCurrentApplications(ctx, applicationSetInfo) - if err != nil { - return ctrl.Result{}, fmt.Errorf("failed to get current applications for application set: %w", err) - } + if r.EnableProgressiveSyncs { + if applicationSetInfo.Spec.Strategy == nil && len(applicationSetInfo.Status.ApplicationStatus) > 0 { + // 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) - for _, app := range applications { - appMap[app.Name] = app - } + 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 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) + } - appSyncMap, err = r.performProgressiveRollouts(ctx, applicationSetInfo, applications, desiredApplications, appMap) - if err != nil { - return ctrl.Result{}, fmt.Errorf("failed to perform progressive rollouts reconciliation for application set: %w", err) + for _, app := range applications { + appMap[app.Name] = app + } + + 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) + } } } @@ -186,10 +225,10 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque ) } - if r.EnableProgressiveRollouts { + if r.EnableProgressiveSyncs { // trigger appropriate application syncs if RollingSync strategy is enabled - if progressiveRolloutStrategyEnabled(&applicationSetInfo, "RollingSync") { - validApps, err = r.syncValidApplications(ctx, &applicationSetInfo, appSyncMap, appMap, validApps) + if progressiveSyncsStrategyEnabled(&applicationSetInfo, "RollingSync") { + validApps, err = r.syncValidApplications(logCtx, &applicationSetInfo, appSyncMap, appMap, validApps) if err != nil { _ = r.setApplicationSetStatusCondition(ctx, @@ -206,8 +245,8 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque } } - if r.Policy.Update() { - err = r.createOrUpdateInCluster(ctx, applicationSetInfo, validApps) + if utils.DefaultPolicy(applicationSetInfo.Spec.SyncPolicy, r.Policy, r.EnablePolicyOverride).AllowUpdate() { + err = r.createOrUpdateInCluster(ctx, logCtx, applicationSetInfo, validApps) if err != nil { _ = r.setApplicationSetStatusCondition(ctx, &applicationSetInfo, @@ -221,7 +260,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, @@ -236,8 +275,8 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque } } - if r.Policy.Delete() { - err = r.deleteInCluster(ctx, applicationSetInfo, desiredApplications) + if utils.DefaultPolicy(applicationSetInfo.Spec.SyncPolicy, r.Policy, r.EnablePolicyOverride).AllowDelete() { + err = r.deleteInCluster(ctx, logCtx, applicationSetInfo, desiredApplications) if err != nil { _ = r.setApplicationSetStatusCondition(ctx, &applicationSetInfo, @@ -271,9 +310,8 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque } requeueAfter := r.getMinRequeueAfter(&applicationSetInfo) - logCtx.WithField("requeueAfter", requeueAfter).Info("end reconcile") - if len(validateErrors) == 0 { + if len(validateErrors) == 0 && generatorsErr == nil { if err := r.setApplicationSetStatusCondition(ctx, &applicationSetInfo, argov1alpha1.ApplicationSetCondition{ @@ -285,8 +323,13 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque ); err != nil { return ctrl.Result{}, err } + } else if requeueAfter == time.Duration(0) { + // Ensure that the request is requeued if there are validation errors. + requeueAfter = ReconcileRequeueOnValidationError } + logCtx.WithField("requeueAfter", requeueAfter).Info("end reconcile") + return ctrl.Result{ RequeueAfter: requeueAfter, }, nil @@ -396,7 +439,7 @@ func (r *ApplicationSetReconciler) setApplicationSetStatusCondition(ctx context. // validateGeneratedApplications uses the Argo CD validation functions to verify the correctness of the // generated applications. -func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Context, desiredApplications []argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet, namespace string) (map[int]error, error) { +func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Context, desiredApplications []argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet) (map[int]error, error) { errorsByIndex := map[int]error{} namesSet := map[string]bool{} for i, app := range desiredApplications { @@ -407,8 +450,7 @@ func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Con errorsByIndex[i] = fmt.Errorf("ApplicationSet %s contains applications with duplicate name: %s", applicationSetInfo.Name, app.Name) continue } - - proj, err := r.ArgoAppClientset.ArgoprojV1alpha1().AppProjects(namespace).Get(ctx, app.Spec.GetProject(), metav1.GetOptions{}) + _, err := r.ArgoAppClientset.ArgoprojV1alpha1().AppProjects(r.ArgoCDNamespace).Get(ctx, app.Spec.GetProject(), metav1.GetOptions{}) if err != nil { if apierr.IsNotFound(err) { errorsByIndex[i] = fmt.Errorf("application references project %s which does not exist", app.Spec.Project) @@ -417,20 +459,11 @@ func (r *ApplicationSetReconciler) validateGeneratedApplications(ctx context.Con return nil, err } - if err := utils.ValidateDestination(ctx, &app.Spec.Destination, r.KubeClientset, namespace); err != nil { + if err := utils.ValidateDestination(ctx, &app.Spec.Destination, r.KubeClientset, r.ArgoCDNamespace); err != nil { errorsByIndex[i] = fmt.Errorf("application destination spec is invalid: %s", err.Error()) continue } - conditions, err := argoutil.ValidatePermissions(ctx, &app.Spec, proj, r.ArgoDB) - if err != nil { - return nil, err - } - if len(conditions) > 0 { - errorsByIndex[i] = fmt.Errorf("application spec is invalid: %s", argoutil.FormatAppConditions(conditions)) - continue - } - } return errorsByIndex, nil @@ -468,7 +501,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 @@ -477,7 +510,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 @@ -490,9 +523,10 @@ func (r *ApplicationSetReconciler) generateApplications(applicationSetInfo argov tmplApplication := getTempApplication(a.Template) for _, p := range a.Params { - app, err := r.Renderer.RenderTemplateParams(tmplApplication, applicationSetInfo.Spec.SyncPolicy, p, applicationSetInfo.Spec.GoTemplate) + 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 { @@ -501,39 +535,81 @@ 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) SetupWithManager(mgr ctrl.Manager) 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 (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 { + return glob.MatchStringInList(namespaces, e.Object.GetNamespace(), false) + }, + } +} + +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) } - return ctrl.NewControllerManagedBy(mgr). - For(&argov1alpha1.ApplicationSet{}). - Owns(&argov1alpha1.Application{}). + ownsHandler := getOwnsHandlerPredicates(enableProgressiveSyncs) + + return ctrl.NewControllerManagedBy(mgr).WithOptions(controller.Options{ + MaxConcurrentReconciles: maxConcurrentReconciliations, + }).For(&argov1alpha1.ApplicationSet{}). + Owns(&argov1alpha1.Application{}, builder.WithPredicates(ownsHandler)). + WithEventFilter(ignoreNotAllowedNamespaces(r.ApplicationSetNamespaces)). Watches( &source.Kind{Type: &corev1.Secret{}}, &clusterSecretEventHandler{ @@ -544,31 +620,55 @@ func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager) error { Complete(r) } +func (r *ApplicationSetReconciler) updateCache(ctx context.Context, obj client.Object, logger *log.Entry) { + informer, err := r.Cache.GetInformer(ctx, obj) + if err != nil { + logger.Errorf("failed to get informer: %v", err) + return + } + // The controller runtime abstract away informers creation + // so unfortunately could not find any other way to access informer store. + k8sInformer, ok := informer.(k8scache.SharedInformer) + if !ok { + logger.Error("informer is not a kubernetes informer") + return + } + if err := k8sInformer.GetStore().Update(obj); err != nil { + logger.Errorf("failed to update cache: %v", err) + return + } +} + // createOrUpdateInCluster will create / update application resources in the cluster. // - 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) + found := &argov1alpha1.Application{ ObjectMeta: metav1.ObjectMeta{ Name: generatedApp.Name, Namespace: generatedApp.Namespace, }, TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, } - 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 @@ -577,9 +677,27 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context, found.Operation = generatedApp.Operation } + preservedAnnotations := make([]string, 0) + preservedLabels := make([]string, 0) + + if applicationSet.Spec.PreservedFields != nil { + preservedAnnotations = append(preservedAnnotations, applicationSet.Spec.PreservedFields.Annotations...) + preservedLabels = append(preservedLabels, applicationSet.Spec.PreservedFields.Labels...) + } + + if len(r.GlobalPreservedAnnotations) > 0 { + preservedAnnotations = append(preservedAnnotations, r.GlobalPreservedAnnotations...) + } + + if len(r.GlobalPreservedLabels) > 0 { + preservedLabels = append(preservedLabels, r.GlobalPreservedLabels...) + } + // Preserve specially treated argo cd annotations: // * https://github.com/argoproj/applicationset/issues/180 // * https://github.com/argoproj/argo-cd/issues/10500 + preservedAnnotations = append(preservedAnnotations, defaultPreservedAnnotations...) + for _, key := range preservedAnnotations { if state, exists := found.ObjectMeta.Annotations[key]; exists { if generatedApp.Annotations == nil { @@ -588,10 +706,21 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context, generatedApp.Annotations[key] = state } } + + for _, key := range preservedLabels { + if state, exists := found.ObjectMeta.Labels[key]; exists { + if generatedApp.Labels == nil { + generatedApp.Labels = map[string]string{} + } + generatedApp.Labels[key] = state + } + } + found.ObjectMeta.Annotations = generatedApp.Annotations found.ObjectMeta.Finalizers = generatedApp.Finalizers found.ObjectMeta.Labels = generatedApp.Labels + return controllerutil.SetControllerReference(&applicationSet, found, r.Scheme) }) @@ -602,16 +731,24 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context, } continue } + r.updateCache(ctx, found, appLog) - r.Recorder.Eventf(&applicationSet, corev1.EventTypeNormal, fmt.Sprint(action), "%s Application %q", action, generatedApp.Name) - appLog.Logf(log.InfoLevel, "%s Application", action) + if action != controllerutil.OperationResultNone { + // Don't pollute etcd with "unchanged Application" events + r.Recorder.Eventf(&applicationSet, corev1.EventTypeNormal, fmt.Sprint(action), "%s Application %q", action, generatedApp.Name) + appLog.Logf(log.InfoLevel, "%s Application", action) + } else { + // "unchanged Application" can be inferred by Reconcile Complete with no action being listed + // Or enable debug logging + appLog.Logf(log.DebugLevel, "%s Application", action) + } } return firstError } // 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) @@ -634,16 +771,15 @@ 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, err + return nil, fmt.Errorf("error retrieving applications: %w", err) } return current.Items, nil @@ -651,11 +787,11 @@ 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) - clusterList, err := utils.ListClusters(ctx, r.KubeClientset, applicationSet.Namespace) + clusterList, err := utils.ListClusters(ctx, r.KubeClientset, r.ArgoCDNamespace) if err != nil { return fmt.Errorf("error listing clusters: %w", err) } @@ -675,15 +811,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 } @@ -692,14 +828,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 @@ -716,7 +852,7 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte var validDestination bool // Detect if the destination is invalid (name doesn't correspond to a matching cluster) - if err := utils.ValidateDestination(ctx, &app.Spec.Destination, r.KubeClientset, applicationSet.Namespace); err != nil { + if err := utils.ValidateDestination(ctx, &app.Spec.Destination, r.KubeClientset, r.ArgoCDNamespace); err != nil { appLog.Warnf("The destination cluster for %s couldn't be found: %v", app.Name, err) validDestination = false } else { @@ -760,31 +896,59 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte // If the finalizer length changed (due to filtering out an Argo finalizer), update the finalizer list on the app if len(newFinalizers) != len(app.Finalizers) { - app.Finalizers = newFinalizers + updated := app.DeepCopy() + updated.Finalizers = newFinalizers + 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) + // Application must have updated list of finalizers + updated.DeepCopyInto(app) r.Recorder.Eventf(&applicationSet, corev1.EventTypeNormal, "Updated", "Updated Application %q finalizer before deletion, because application has an invalid destination", app.Name) appLog.Log(log.InfoLevel, "Updating application finalizer before deletion, because application has an invalid destination") + } + } - err := r.Client.Update(ctx, app, &client.UpdateOptions{}) - if err != nil { - return fmt.Errorf("error updating finalizers: %w", err) - } + return nil +} + +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) performProgressiveRollouts(ctx context.Context, appset argov1alpha1.ApplicationSet, applications []argov1alpha1.Application, desiredApplications []argov1alpha1.Application, appMap map[string]argov1alpha1.Application) (map[string]bool, error) { +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) { - _, err := r.updateApplicationSetApplicationStatus(ctx, &appset, applications) + appDependencyList, appStepMap, err := r.buildAppDependencyList(logCtx, appset, desiredApplications) if err != nil { - return nil, fmt.Errorf("failed to update applicationset app status: %w", err) + return nil, fmt.Errorf("failed to build app dependency list: %w", err) } - appDependencyList, appStepMap, err := r.buildAppDependencyList(ctx, appset, desiredApplications) + _, err = r.updateApplicationSetApplicationStatus(ctx, logCtx, &appset, applications, appStepMap) if err != nil { - return nil, fmt.Errorf("failed to build app dependency list: %w", err) + return nil, fmt.Errorf("failed to update applicationset app status: %w", err) + } + + logCtx.Infof("ApplicationSet %v step list:", appset.Name) + for i, step := range appDependencyList { + logCtx.Infof("step %v: %+v", i+1, step) } appSyncMap, err := r.buildAppSyncMap(ctx, appset, appDependencyList, appMap) @@ -792,9 +956,9 @@ func (r *ApplicationSetReconciler) performProgressiveRollouts(ctx context.Contex return nil, fmt.Errorf("failed to build app sync map: %w", err) } - log.Infof("appSyncMap: %+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) } @@ -808,14 +972,14 @@ func (r *ApplicationSetReconciler) performProgressiveRollouts(ctx context.Contex } // 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 } steps := []argov1alpha1.ApplicationSetRolloutStep{} - if progressiveRolloutStrategyEnabled(&applicationSet, "RollingSync") { + if progressiveSyncsStrategyEnabled(&applicationSet, "RollingSync") { steps = applicationSet.Spec.Strategy.RollingSync.Steps } @@ -832,49 +996,25 @@ func (r *ApplicationSetReconciler) buildAppDependencyList(ctx context.Context, a selected := true // default to true, assuming the current Application is a match for the given step matchExpression - allNotInMatched := true // needed to support correct AND behavior between multiple NotIn MatchExpressions - notInUsed := false // since we default to allNotInMatched == true, track whether a NotIn expression was actually used - for _, matchExpression := range step.MatchExpressions { - if matchExpression.Operator == "In" { - if val, ok := app.Labels[matchExpression.Key]; ok { - valueMatched := labelMatchedExpression(val, matchExpression) + if val, ok := app.Labels[matchExpression.Key]; ok { + valueMatched := labelMatchedExpression(logCtx, val, matchExpression) - if !valueMatched { // none of the matchExpression values was a match with the Application'ss labels - selected = false - break - } - } else { - selected = false // no matching label key with In means this Application will not be included in the current step + if !valueMatched { // none of the matchExpression values was a match with the Application's labels + selected = false break } - } else if matchExpression.Operator == "NotIn" { - notInUsed = true // a NotIn selector was used in this matchExpression - if val, ok := app.Labels[matchExpression.Key]; ok { - valueMatched := labelMatchedExpression(val, matchExpression) - - if !valueMatched { // none of the matchExpression values was a match with the Application's labels - allNotInMatched = false - } - } else { - allNotInMatched = false // no matching label key with NotIn means this Application may still be included in the current step - } - } else { // handle invalid operator selection - log.Warnf("skipping AppSet rollingUpdate step Application selection for %q, invalid matchExpression operator provided: %q ", applicationSet.Name, matchExpression.Operator) - selected = false + } else if matchExpression.Operator == "In" { + selected = false // no matching label key with "In" operator means this Application will not be included in the current step break } } - if notInUsed && allNotInMatched { // check if all NotIn Expressions matched, if so exclude this Application - selected = false - } - 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 } @@ -885,12 +1025,21 @@ func (r *ApplicationSetReconciler) buildAppDependencyList(ctx context.Context, a return appDependencyList, appStepMap, nil } -func labelMatchedExpression(val string, matchExpression argov1alpha1.ApplicationMatchExpression) bool { - valueMatched := false +func labelMatchedExpression(logCtx *log.Entry, val string, matchExpression argov1alpha1.ApplicationMatchExpression) bool { + if matchExpression.Operator != "In" && matchExpression.Operator != "NotIn" { + logCtx.Errorf("skipping AppSet rollingUpdate step Application selection, invalid matchExpression operator provided: %q ", matchExpression.Operator) + return false + } + + // if operator == In, default to false + // if operator == NotIn, default to true + valueMatched := matchExpression.Operator == "NotIn" + for _, value := range matchExpression.Values { if val == value { - valueMatched = true - break + // first "In" match returns true + // first "NotIn" match returns false + return matchExpression.Operator == "In" } } return valueMatched @@ -941,7 +1090,7 @@ func (r *ApplicationSetReconciler) buildAppSyncMap(ctx context.Context, applicat func appSyncEnabledForNextStep(appset *argov1alpha1.ApplicationSet, app argov1alpha1.Application, appStatus argov1alpha1.ApplicationSetApplicationStatus) bool { - if progressiveRolloutStrategyEnabled(appset, "RollingSync") { + if progressiveSyncsStrategyEnabled(appset, "RollingSync") { // we still need to complete the current step if the Application is not yet Healthy or there are still pending Application changes return isApplicationHealthy(app) && appStatus.Status == "Healthy" } @@ -949,7 +1098,7 @@ func appSyncEnabledForNextStep(appset *argov1alpha1.ApplicationSet, app argov1al return true } -func progressiveRolloutStrategyEnabled(appset *argov1alpha1.ApplicationSet, strategyType string) bool { +func progressiveSyncsStrategyEnabled(appset *argov1alpha1.ApplicationSet, strategyType string) bool { if appset.Spec.Strategy == nil || appset.Spec.Strategy.Type != strategyType { return false } @@ -982,7 +1131,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) ([]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)) @@ -993,59 +1142,76 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con idx := findApplicationStatusIndex(applicationSet.Status.ApplicationStatus, app.Name) + currentAppStatus := argov1alpha1.ApplicationSetApplicationStatus{} + if idx == -1 { // AppStatus not found, set default status of "Waiting" - appStatuses = append(appStatuses, argov1alpha1.ApplicationSetApplicationStatus{ + currentAppStatus = argov1alpha1.ApplicationSetApplicationStatus{ Application: app.Name, LastTransitionTime: &now, Message: "No Application status found, defaulting status to Waiting.", Status: "Waiting", - }) - break + Step: fmt.Sprint(appStepMap[app.Name] + 1), + } + } else { + // we have an existing AppStatus + currentAppStatus = applicationSet.Status.ApplicationStatus[idx] } - // we have an existing AppStatus - currentAppStatus := applicationSet.Status.ApplicationStatus[idx] - appOutdated := false - if progressiveRolloutStrategyEnabled(applicationSet, "RollingSync") { + if progressiveSyncsStrategyEnabled(applicationSet, "RollingSync") { appOutdated = syncStatusString == "OutOfSync" } 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." + currentAppStatus.Step = fmt.Sprint(appStepMap[currentAppStatus.Application] + 1) } if currentAppStatus.Status == "Pending" { - if healthStatusString == "Progressing" || operationPhaseString == "Running" { - log.Infof("Application %v has entered Progressing status, updating its ApplicationSet status to Progressing", app.Name) + // check for successful syncs started less than 10s before the Application transitioned to Pending + // 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) { + 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) + } + 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" { + 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." + currentAppStatus.Step = fmt.Sprint(appStepMap[currentAppStatus.Application] + 1) } } 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." + currentAppStatus.Step = fmt.Sprint(appStepMap[currentAppStatus.Application] + 1) } 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." + currentAppStatus.Step = fmt.Sprint(appStepMap[currentAppStatus.Application] + 1) } 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) } @@ -1054,7 +1220,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)) @@ -1065,7 +1231,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress totalCountMap := []int{} length := 0 - if progressiveRolloutStrategyEnabled(applicationSet, "RollingSync") { + if progressiveSyncsStrategyEnabled(applicationSet, "RollingSync") { length = len(applicationSet.Spec.Strategy.RollingSync.Steps) } for s := 0; s < length; s++ { @@ -1077,7 +1243,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress for _, appStatus := range applicationSet.Status.ApplicationStatus { totalCountMap[appStepMap[appStatus.Application]] += 1 - if progressiveRolloutStrategyEnabled(applicationSet, "RollingSync") { + if progressiveSyncsStrategyEnabled(applicationSet, "RollingSync") { if appStatus.Status == "Pending" || appStatus.Status == "Progressing" { updateCountMap[appStepMap[appStatus.Application]] += 1 } @@ -1088,7 +1254,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress maxUpdateAllowed := true maxUpdate := &intstr.IntOrString{} - if progressiveRolloutStrategyEnabled(applicationSet, "RollingSync") { + if progressiveSyncsStrategyEnabled(applicationSet, "RollingSync") { maxUpdate = applicationSet.Spec.Strategy.RollingSync.Steps[appStepMap[appStatus.Application]].MaxUpdate } @@ -1096,7 +1262,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 @@ -1106,16 +1272,17 @@ 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." + appStatus.Step = fmt.Sprint(appStepMap[appStatus.Application] + 1) updateCountMap[appStepMap[appStatus.Application]] += 1 } @@ -1124,7 +1291,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) } @@ -1186,32 +1353,32 @@ 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 - for i := range applicationStatuses { - appStatus := applicationStatuses[i] - idx := findApplicationStatusIndex(applicationSet.Status.ApplicationStatus, appStatus.Application) - if idx == -1 { - needToUpdateStatus = true - break - } - currentStatus := applicationSet.Status.ApplicationStatus[idx] - if currentStatus.Message != appStatus.Message || currentStatus.Status != appStatus.Status { - needToUpdateStatus = true - break + + if len(applicationStatuses) != len(applicationSet.Status.ApplicationStatus) { + needToUpdateStatus = true + } else { + for i := range applicationStatuses { + appStatus := applicationStatuses[i] + idx := findApplicationStatusIndex(applicationSet.Status.ApplicationStatus, appStatus.Application) + if idx == -1 { + needToUpdateStatus = true + break + } + currentStatus := applicationSet.Status.ApplicationStatus[idx] + if currentStatus.Message != appStatus.Message || currentStatus.Status != appStatus.Status || currentStatus.Step != appStatus.Step { + needToUpdateStatus = true + break + } } } if needToUpdateStatus { - // fetch updated Application Set object before updating it namespacedName := types.NamespacedName{Namespace: applicationSet.Namespace, Name: applicationSet.Name} - if err := r.Get(ctx, namespacedName, applicationSet); err != nil { - if client.IgnoreNotFound(err) != nil { - return nil - } - return fmt.Errorf("error fetching updated application set: %v", err) - } + // rebuild ApplicationStatus from scratch, we don't need any previous status history + applicationSet.Status.ApplicationStatus = []argov1alpha1.ApplicationSetApplicationStatus{} for i := range applicationStatuses { applicationSet.Status.SetApplicationStatus(applicationStatuses[i]) } @@ -1220,7 +1387,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) } @@ -1235,7 +1402,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 @@ -1255,7 +1422,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]) @@ -1263,7 +1430,7 @@ func (r *ApplicationSetReconciler) syncValidApplications(ctx context.Context, ap return rolloutApps, nil } -// used by the RollingSync Progressive Rollout strategy to trigger a sync of a particular Application resource +// used by the RollingSync Progressive Sync strategy to trigger a sync of a particular Application resource func syncApplication(application argov1alpha1.Application, prune bool) (argov1alpha1.Application, error) { operation := argov1alpha1.Operation{ @@ -1294,4 +1461,95 @@ func syncApplication(application argov1alpha1.Application, prune bool) (argov1al return application, nil } +func getOwnsHandlerPredicates(enableProgressiveSyncs bool) predicate.Funcs { + return 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 + 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 { + 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 { + 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) + logCtx.WithField("requeue", requeue).Debugf("requeue: %t caused by application %s\n", requeue, appNew.Name) + return requeue + }, + GenericFunc: func(e event.GenericEvent) bool { + 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 + }, + } +} + +// shouldRequeueApplicationSet determines when we want to requeue an ApplicationSet for reconciling based on an owned +// application change +// The applicationset controller owns a subset of the Application CR. +// We do not need to re-reconcile if parts of the application change outside the applicationset's control. +// An example being, Application.ApplicationStatus.ReconciledAt which gets updated by the application controller. +// Additionally, Application.ObjectMeta.ResourceVersion and Application.ObjectMeta.Generation which are set by K8s. +func shouldRequeueApplicationSet(appOld *argov1alpha1.Application, appNew *argov1alpha1.Application, enableProgressiveSyncs bool) bool { + if appOld == nil || appNew == nil { + return false + } + + // the applicationset controller owns the application spec, labels, annotations, and finalizers on the applications + if !reflect.DeepEqual(appOld.Spec, appNew.Spec) || + !reflect.DeepEqual(appOld.ObjectMeta.GetAnnotations(), appNew.ObjectMeta.GetAnnotations()) || + !reflect.DeepEqual(appOld.ObjectMeta.GetLabels(), appNew.ObjectMeta.GetLabels()) || + !reflect.DeepEqual(appOld.ObjectMeta.GetFinalizers(), appNew.ObjectMeta.GetFinalizers()) { + return true + } + + // progressive syncs use the application status for updates. if they differ, requeue to trigger the next progression + if enableProgressiveSyncs { + if appOld.Status.Health.Status != appNew.Status.Health.Status || appOld.Status.Sync.Status != appNew.Status.Sync.Status { + return true + } + + if appOld.Status.OperationState != nil && appNew.Status.OperationState != nil { + if appOld.Status.OperationState.Phase != appNew.Status.OperationState.Phase || + appOld.Status.OperationState.StartedAt != appNew.Status.OperationState.StartedAt { + return true + } + } + } + + return false +} + var _ handler.EventHandler = &clusterSecretEventHandler{} diff --git a/applicationset/controllers/applicationset_controller_test.go b/applicationset/controllers/applicationset_controller_test.go index 38b25e8eac4e6..c3c5f3845bea5 100644 --- a/applicationset/controllers/applicationset_controller_test.go +++ b/applicationset/controllers/applicationset_controller_test.go @@ -19,73 +19,118 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" kubefake "k8s.io/client-go/kubernetes/fake" + k8scache "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/cache" crtclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/event" - "github.com/argoproj/argo-cd/v2/applicationset/generators" - "github.com/argoproj/argo-cd/v2/applicationset/utils" "github.com/argoproj/gitops-engine/pkg/health" "github.com/argoproj/gitops-engine/pkg/sync/common" + "github.com/argoproj/argo-cd/v2/applicationset/generators" + "github.com/argoproj/argo-cd/v2/applicationset/utils" + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/fake" "github.com/argoproj/argo-cd/v2/util/collections" dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application" ) +type fakeStore struct { + k8scache.Store +} + +func (f *fakeStore) Update(obj interface{}) error { + return nil +} + +type fakeInformer struct { + k8scache.SharedInformer +} + +func (f *fakeInformer) AddIndexers(indexers k8scache.Indexers) error { + return nil +} + +func (f *fakeInformer) GetStore() k8scache.Store { + return &fakeStore{} +} + +type fakeCache struct { + cache.Cache +} + +func (f *fakeCache) GetInformer(ctx context.Context, obj crtclient.Object) (cache.Informer, error) { + return &fakeInformer{}, nil +} + type generatorMock struct { mock.Mock } -func (g *generatorMock) GetTemplate(appSetGenerator *argov1alpha1.ApplicationSetGenerator) *argov1alpha1.ApplicationSetTemplate { +func (g *generatorMock) GetTemplate(appSetGenerator *v1alpha1.ApplicationSetGenerator) *v1alpha1.ApplicationSetTemplate { args := g.Called(appSetGenerator) - return args.Get(0).(*argov1alpha1.ApplicationSetTemplate) + return args.Get(0).(*v1alpha1.ApplicationSetTemplate) } -func (g *generatorMock) GenerateParams(appSetGenerator *argov1alpha1.ApplicationSetGenerator, _ *argov1alpha1.ApplicationSet) ([]map[string]interface{}, error) { +func (g *generatorMock) GenerateParams(appSetGenerator *v1alpha1.ApplicationSetGenerator, _ *v1alpha1.ApplicationSet) ([]map[string]interface{}, error) { args := g.Called(appSetGenerator) 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 } -func (g *generatorMock) GetRequeueAfter(appSetGenerator *argov1alpha1.ApplicationSetGenerator) time.Duration { +func (g *generatorMock) GetRequeueAfter(appSetGenerator *v1alpha1.ApplicationSetGenerator) time.Duration { args := g.Called(appSetGenerator) return args.Get(0).(time.Duration) } -func (r *rendererMock) RenderTemplateParams(tmpl *argov1alpha1.Application, syncPolicy *argov1alpha1.ApplicationSetSyncPolicy, params map[string]interface{}, useGoTemplate bool) (*argov1alpha1.Application, error) { - args := r.Called(tmpl, params, useGoTemplate) +func (r *rendererMock) RenderTemplateParams(tmpl *v1alpha1.Application, syncPolicy *v1alpha1.ApplicationSetSyncPolicy, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (*v1alpha1.Application, error) { + args := r.Called(tmpl, params, useGoTemplate, goTemplateOptions) if args.Error(1) != nil { return nil, args.Error(1) } - return args.Get(0).(*argov1alpha1.Application), args.Error(1) + return args.Get(0).(*v1alpha1.Application), args.Error(1) + +} + +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 := argov1alpha1.AddToScheme(scheme) + err := v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - err = argov1alpha1.AddToScheme(scheme) + err = v1alpha1.AddToScheme(scheme) assert.Nil(t, err) for _, c := range []struct { name string params []map[string]interface{} - template argov1alpha1.ApplicationSetTemplate + template v1alpha1.ApplicationSetTemplate generateParamsError error rendererError error expectErr bool @@ -94,13 +139,13 @@ func TestExtractApplications(t *testing.T) { { name: "Generate two applications", params: []map[string]interface{}{{"name": "app1"}, {"name": "app2"}}, - template: argov1alpha1.ApplicationSetTemplate{ - ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{ + template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ Name: "name", Namespace: "namespace", Labels: map[string]string{"label_name": "label_value"}, }, - Spec: argov1alpha1.ApplicationSpec{}, + Spec: v1alpha1.ApplicationSpec{}, }, expectedReason: "", }, @@ -113,13 +158,13 @@ func TestExtractApplications(t *testing.T) { { name: "Handles error from the render", params: []map[string]interface{}{{"name": "app1"}, {"name": "app2"}}, - template: argov1alpha1.ApplicationSetTemplate{ - ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{ + template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ Name: "name", Namespace: "namespace", Labels: map[string]string{"label_name": "label_value"}, }, - Spec: argov1alpha1.ApplicationSpec{}, + Spec: v1alpha1.ApplicationSpec{}, }, rendererError: fmt.Errorf("error"), expectErr: true, @@ -127,7 +172,7 @@ func TestExtractApplications(t *testing.T) { }, } { cc := c - app := argov1alpha1.Application{ + app := v1alpha1.Application{ ObjectMeta: metav1.ObjectMeta{ Name: "test", }, @@ -135,7 +180,7 @@ func TestExtractApplications(t *testing.T) { t.Run(cc.name, func(t *testing.T) { - appSet := &argov1alpha1.ApplicationSet{ + appSet := &v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", @@ -145,28 +190,28 @@ func TestExtractApplications(t *testing.T) { client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(appSet).Build() generatorMock := generatorMock{} - generator := argov1alpha1.ApplicationSetGenerator{ - List: &argov1alpha1.ListGenerator{}, + generator := v1alpha1.ApplicationSetGenerator{ + List: &v1alpha1.ListGenerator{}, } generatorMock.On("GenerateParams", &generator). Return(cc.params, cc.generateParamsError) generatorMock.On("GetTemplate", &generator). - Return(&argov1alpha1.ApplicationSetTemplate{}) + Return(&v1alpha1.ApplicationSetTemplate{}) rendererMock := rendererMock{} - var expectedApps []argov1alpha1.Application + var expectedApps []v1alpha1.Application if cc.generateParamsError == nil { for _, p := range cc.params { if cc.rendererError != nil { - rendererMock.On("RenderTemplateParams", getTempApplication(cc.template), p, false). + rendererMock.On("RenderTemplateParams", getTempApplication(cc.template), p, false, []string(nil)). Return(nil, cc.rendererError) } else { - rendererMock.On("RenderTemplateParams", getTempApplication(cc.template), p, false). + rendererMock.On("RenderTemplateParams", getTempApplication(cc.template), p, false, []string(nil)). Return(&app, nil) expectedApps = append(expectedApps, app) } @@ -182,15 +227,16 @@ func TestExtractApplications(t *testing.T) { }, Renderer: &rendererMock, KubeClientset: kubefake.NewSimpleClientset(), + Cache: &fakeCache{}, } - got, reason, err := r.generateApplications(argov1alpha1.ApplicationSet{ + got, reason, err := r.generateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Generators: []argov1alpha1.ApplicationSetGenerator{generator}, + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{generator}, Template: cc.template, }, }) @@ -215,53 +261,53 @@ func TestExtractApplications(t *testing.T) { func TestMergeTemplateApplications(t *testing.T) { scheme := runtime.NewScheme() - _ = argov1alpha1.AddToScheme(scheme) - _ = argov1alpha1.AddToScheme(scheme) + _ = v1alpha1.AddToScheme(scheme) + _ = v1alpha1.AddToScheme(scheme) client := fake.NewClientBuilder().WithScheme(scheme).Build() for _, c := range []struct { name string params []map[string]interface{} - template argov1alpha1.ApplicationSetTemplate - overrideTemplate argov1alpha1.ApplicationSetTemplate - expectedMerged argov1alpha1.ApplicationSetTemplate - expectedApps []argov1alpha1.Application + template v1alpha1.ApplicationSetTemplate + overrideTemplate v1alpha1.ApplicationSetTemplate + expectedMerged v1alpha1.ApplicationSetTemplate + expectedApps []v1alpha1.Application }{ { name: "Generate app", params: []map[string]interface{}{{"name": "app1"}}, - template: argov1alpha1.ApplicationSetTemplate{ - ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{ + template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ Name: "name", Namespace: "namespace", Labels: map[string]string{"label_name": "label_value"}, }, - Spec: argov1alpha1.ApplicationSpec{}, + Spec: v1alpha1.ApplicationSpec{}, }, - overrideTemplate: argov1alpha1.ApplicationSetTemplate{ - ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{ + overrideTemplate: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ Name: "test", Labels: map[string]string{"foo": "bar"}, }, - Spec: argov1alpha1.ApplicationSpec{}, + Spec: v1alpha1.ApplicationSpec{}, }, - expectedMerged: argov1alpha1.ApplicationSetTemplate{ - ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{ + expectedMerged: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ Name: "test", Namespace: "namespace", Labels: map[string]string{"label_name": "label_value", "foo": "bar"}, }, - Spec: argov1alpha1.ApplicationSpec{}, + Spec: v1alpha1.ApplicationSpec{}, }, - expectedApps: []argov1alpha1.Application{ + expectedApps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: "test", Labels: map[string]string{"foo": "bar"}, }, - Spec: argov1alpha1.ApplicationSpec{}, + Spec: v1alpha1.ApplicationSpec{}, }, }, }, @@ -271,8 +317,8 @@ func TestMergeTemplateApplications(t *testing.T) { t.Run(cc.name, func(t *testing.T) { generatorMock := generatorMock{} - generator := argov1alpha1.ApplicationSetGenerator{ - List: &argov1alpha1.ListGenerator{}, + generator := v1alpha1.ApplicationSetGenerator{ + List: &v1alpha1.ListGenerator{}, } generatorMock.On("GenerateParams", &generator). @@ -283,7 +329,7 @@ func TestMergeTemplateApplications(t *testing.T) { rendererMock := rendererMock{} - rendererMock.On("RenderTemplateParams", getTempApplication(cc.expectedMerged), cc.params[0], false). + rendererMock.On("RenderTemplateParams", getTempApplication(cc.expectedMerged), cc.params[0], false, []string(nil)). Return(&cc.expectedApps[0], nil) r := ApplicationSetReconciler{ @@ -297,13 +343,13 @@ func TestMergeTemplateApplications(t *testing.T) { KubeClientset: kubefake.NewSimpleClientset(), } - got, _, _ := r.generateApplications(argov1alpha1.ApplicationSet{ + got, _, _ := r.generateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Generators: []argov1alpha1.ApplicationSetGenerator{generator}, + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{generator}, Template: cc.template, }, }, @@ -318,44 +364,44 @@ func TestMergeTemplateApplications(t *testing.T) { func TestCreateOrUpdateInCluster(t *testing.T) { scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) + err := v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - err = argov1alpha1.AddToScheme(scheme) + err = v1alpha1.AddToScheme(scheme) assert.Nil(t, err) for _, c := range []struct { // name is human-readable test name name string // appSet is the ApplicationSet we are generating resources for - appSet argov1alpha1.ApplicationSet + appSet v1alpha1.ApplicationSet // existingApps are the apps that already exist on the cluster - existingApps []argov1alpha1.Application + existingApps []v1alpha1.Application // desiredApps are the generated apps to create/update - desiredApps []argov1alpha1.Application + desiredApps []v1alpha1.Application // expected is what we expect the cluster Applications to look like, after createOrUpdateInCluster - expected []argov1alpha1.Application + expected []v1alpha1.Application }{ { name: "Create an app that doesn't exist", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, }, existingApps: nil, - desiredApps: []argov1alpha1.Application{ + desiredApps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, }, }, - expected: []argov1alpha1.Application{ + expected: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -363,28 +409,29 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", ResourceVersion: "1", }, + Spec: v1alpha1.ApplicationSpec{Project: "default"}, }, }, }, { name: "Update an existing app with a different project name", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Template: argov1alpha1.ApplicationSetTemplate{ - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, }, - existingApps: []argov1alpha1.Application{ + existingApps: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -392,25 +439,25 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", ResourceVersion: "2", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "test", }, }, }, - desiredApps: []argov1alpha1.Application{ + desiredApps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, - expected: []argov1alpha1.Application{ + expected: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -418,7 +465,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", ResourceVersion: "3", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, @@ -426,23 +473,23 @@ func TestCreateOrUpdateInCluster(t *testing.T) { }, { name: "Create a new app and check it doesn't replace the existing app", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Template: argov1alpha1.ApplicationSetTemplate{ - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, }, - existingApps: []argov1alpha1.Application{ + existingApps: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -450,25 +497,25 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", ResourceVersion: "2", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "test", }, }, }, - desiredApps: []argov1alpha1.Application{ + desiredApps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app2", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, - expected: []argov1alpha1.Application{ + expected: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -476,7 +523,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", ResourceVersion: "1", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, @@ -484,23 +531,23 @@ func TestCreateOrUpdateInCluster(t *testing.T) { }, { name: "Ensure that labels and annotations are added (via update) into an exiting application", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Template: argov1alpha1.ApplicationSetTemplate{ - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, }, - existingApps: []argov1alpha1.Application{ + existingApps: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -508,27 +555,27 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", ResourceVersion: "2", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, - desiredApps: []argov1alpha1.Application{ + desiredApps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", Labels: map[string]string{"label-key": "label-value"}, Annotations: map[string]string{"annot-key": "annot-value"}, }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, - expected: []argov1alpha1.Application{ + expected: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -538,7 +585,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Annotations: map[string]string{"annot-key": "annot-value"}, ResourceVersion: "3", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, @@ -546,23 +593,23 @@ func TestCreateOrUpdateInCluster(t *testing.T) { }, { name: "Ensure that labels and annotations are removed from an existing app", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Template: argov1alpha1.ApplicationSetTemplate{ - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, }, - existingApps: []argov1alpha1.Application{ + existingApps: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -572,25 +619,25 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Labels: map[string]string{"label-key": "label-value"}, Annotations: map[string]string{"annot-key": "annot-value"}, }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, - desiredApps: []argov1alpha1.Application{ + desiredApps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, - expected: []argov1alpha1.Application{ + expected: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -598,7 +645,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", ResourceVersion: "3", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, @@ -606,23 +653,23 @@ func TestCreateOrUpdateInCluster(t *testing.T) { }, { name: "Ensure that status and operation fields are not overridden by an update, when removing labels/annotations", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Template: argov1alpha1.ApplicationSetTemplate{ - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, }, - existingApps: []argov1alpha1.Application{ + existingApps: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -632,31 +679,31 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Labels: map[string]string{"label-key": "label-value"}, Annotations: map[string]string{"annot-key": "annot-value"}, }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, - Status: argov1alpha1.ApplicationStatus{ - Resources: []argov1alpha1.ResourceStatus{{Name: "sample-name"}}, + Status: v1alpha1.ApplicationStatus{ + Resources: []v1alpha1.ResourceStatus{{Name: "sample-name"}}, }, - Operation: &argov1alpha1.Operation{ - Sync: &argov1alpha1.SyncOperation{Revision: "sample-revision"}, + Operation: &v1alpha1.Operation{ + Sync: &v1alpha1.SyncOperation{Revision: "sample-revision"}, }, }, }, - desiredApps: []argov1alpha1.Application{ + desiredApps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, - expected: []argov1alpha1.Application{ + expected: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -664,39 +711,39 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", ResourceVersion: "3", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, - Status: argov1alpha1.ApplicationStatus{ - Resources: []argov1alpha1.ResourceStatus{{Name: "sample-name"}}, + Status: v1alpha1.ApplicationStatus{ + Resources: []v1alpha1.ResourceStatus{{Name: "sample-name"}}, }, - Operation: &argov1alpha1.Operation{ - Sync: &argov1alpha1.SyncOperation{Revision: "sample-revision"}, + Operation: &v1alpha1.Operation{ + Sync: &v1alpha1.SyncOperation{Revision: "sample-revision"}, }, }, }, }, { name: "Ensure that status and operation fields are not overridden by an update, when removing labels/annotations and adding other fields", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Template: argov1alpha1.ApplicationSetTemplate{ - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", - Source: &argov1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"}, - Destination: argov1alpha1.ApplicationDestination{Server: "server", Namespace: "namespace"}, + Source: &v1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"}, + Destination: v1alpha1.ApplicationDestination{Server: "server", Namespace: "namespace"}, }, }, }, }, - existingApps: []argov1alpha1.Application{ + existingApps: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -704,35 +751,35 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", ResourceVersion: "2", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, - Status: argov1alpha1.ApplicationStatus{ - Resources: []argov1alpha1.ResourceStatus{{Name: "sample-name"}}, + Status: v1alpha1.ApplicationStatus{ + Resources: []v1alpha1.ResourceStatus{{Name: "sample-name"}}, }, - Operation: &argov1alpha1.Operation{ - Sync: &argov1alpha1.SyncOperation{Revision: "sample-revision"}, + Operation: &v1alpha1.Operation{ + Sync: &v1alpha1.SyncOperation{Revision: "sample-revision"}, }, }, }, - desiredApps: []argov1alpha1.Application{ + desiredApps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", Labels: map[string]string{"label-key": "label-value"}, Annotations: map[string]string{"annot-key": "annot-value"}, }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", - Source: &argov1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"}, - Destination: argov1alpha1.ApplicationDestination{Server: "server", Namespace: "namespace"}, + Source: &v1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"}, + Destination: v1alpha1.ApplicationDestination{Server: "server", Namespace: "namespace"}, }, }, }, - expected: []argov1alpha1.Application{ + expected: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -742,39 +789,39 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Annotations: map[string]string{"annot-key": "annot-value"}, ResourceVersion: "3", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", - Source: &argov1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"}, - Destination: argov1alpha1.ApplicationDestination{Server: "server", Namespace: "namespace"}, + Source: &v1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"}, + Destination: v1alpha1.ApplicationDestination{Server: "server", Namespace: "namespace"}, }, - Status: argov1alpha1.ApplicationStatus{ - Resources: []argov1alpha1.ResourceStatus{{Name: "sample-name"}}, + Status: v1alpha1.ApplicationStatus{ + Resources: []v1alpha1.ResourceStatus{{Name: "sample-name"}}, }, - Operation: &argov1alpha1.Operation{ - Sync: &argov1alpha1.SyncOperation{Revision: "sample-revision"}, + Operation: &v1alpha1.Operation{ + Sync: &v1alpha1.SyncOperation{Revision: "sample-revision"}, }, }, }, }, { name: "Ensure that argocd notifications state and refresh annotation is preserved from an existing app", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Template: argov1alpha1.ApplicationSetTemplate{ - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, }, - existingApps: []argov1alpha1.Application{ + existingApps: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -783,30 +830,30 @@ func TestCreateOrUpdateInCluster(t *testing.T) { ResourceVersion: "2", Labels: map[string]string{"label-key": "label-value"}, Annotations: map[string]string{ - "annot-key": "annot-value", - NotifiedAnnotationKey: `{"b620d4600c771a6f4cxxxxxxx:on-deployed:[0].y7b5sbwa2Q329JYHxxxxxx-fBs:slack:slack-test":1617144614}`, - argov1alpha1.AnnotationKeyRefresh: string(argov1alpha1.RefreshTypeNormal), + "annot-key": "annot-value", + NotifiedAnnotationKey: `{"b620d4600c771a6f4cxxxxxxx:on-deployed:[0].y7b5sbwa2Q329JYHxxxxxx-fBs:slack:slack-test":1617144614}`, + v1alpha1.AnnotationKeyRefresh: string(v1alpha1.RefreshTypeNormal), }, }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, - desiredApps: []argov1alpha1.Application{ + desiredApps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, - expected: []argov1alpha1.Application{ + expected: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -814,368 +861,201 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", ResourceVersion: "3", Annotations: map[string]string{ - NotifiedAnnotationKey: `{"b620d4600c771a6f4cxxxxxxx:on-deployed:[0].y7b5sbwa2Q329JYHxxxxxx-fBs:slack:slack-test":1617144614}`, - argov1alpha1.AnnotationKeyRefresh: string(argov1alpha1.RefreshTypeNormal), + NotifiedAnnotationKey: `{"b620d4600c771a6f4cxxxxxxx:on-deployed:[0].y7b5sbwa2Q329JYHxxxxxx-fBs:slack:slack-test":1617144614}`, + v1alpha1.AnnotationKeyRefresh: string(v1alpha1.RefreshTypeNormal), }, }, - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, - }, - } { - - t.Run(c.name, func(t *testing.T) { - - initObjs := []crtclient.Object{&c.appSet} - - for _, a := range c.existingApps { - err = controllerutil.SetControllerReference(&c.appSet, &a, scheme) - assert.Nil(t, err) - initObjs = append(initObjs, &a) - } - - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).Build() - - r := ApplicationSetReconciler{ - Client: client, - Scheme: scheme, - Recorder: record.NewFakeRecorder(len(initObjs) + len(c.expected)), - } - - err = r.createOrUpdateInCluster(context.TODO(), c.appSet, c.desiredApps) - assert.Nil(t, err) - - for _, obj := range c.expected { - got := &argov1alpha1.Application{} - _ = client.Get(context.Background(), crtclient.ObjectKey{ - Namespace: obj.Namespace, - Name: obj.Name, - }, got) - - err = controllerutil.SetControllerReference(&c.appSet, &obj, r.Scheme) - assert.Nil(t, err) - assert.Equal(t, obj, *got) - } - }) - } -} - -func TestRemoveFinalizerOnInvalidDestination_FinalizerTypes(t *testing.T) { - - scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) - assert.Nil(t, err) - - err = argov1alpha1.AddToScheme(scheme) - assert.Nil(t, err) - - for _, c := range []struct { - // name is human-readable test name - name string - existingFinalizers []string - expectedFinalizers []string - }{ - { - name: "no finalizers", - existingFinalizers: []string{}, - expectedFinalizers: nil, - }, - { - name: "contains only argo finalizer", - existingFinalizers: []string{argov1alpha1.ResourcesFinalizerName}, - expectedFinalizers: nil, - }, - { - name: "contains only non-argo finalizer", - existingFinalizers: []string{"non-argo-finalizer"}, - expectedFinalizers: []string{"non-argo-finalizer"}, - }, - { - name: "contains both argo and non-argo finalizer", - existingFinalizers: []string{"non-argo-finalizer", argov1alpha1.ResourcesFinalizerName}, - expectedFinalizers: []string{"non-argo-finalizer"}, - }, - } { - t.Run(c.name, func(t *testing.T) { - - appSet := argov1alpha1.ApplicationSet{ + }, { + name: "Ensure that configured preserved annotations are preserved from an existing app", + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Template: argov1alpha1.ApplicationSetTemplate{ - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, + PreservedFields: &v1alpha1.ApplicationPreservedFields{ + Annotations: []string{"preserved-annot-key"}, + }, }, - } - - app := argov1alpha1.Application{ + }, + existingApps: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + ResourceVersion: "2", + Annotations: map[string]string{ + "annot-key": "annot-value", + "preserved-annot-key": "preserved-annot-value", + }, + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + desiredApps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + expected: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + ResourceVersion: "3", + Annotations: map[string]string{ + "preserved-annot-key": "preserved-annot-value", + }, + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + }, { + name: "Ensure that the app spec is normalized before applying", + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ - Name: "app1", - Finalizers: c.existingFinalizers, + Name: "name", + Namespace: "namespace", }, - Spec: argov1alpha1.ApplicationSpec{ - Project: "project", - Source: &argov1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"}, - // Destination is always invalid, for this test: - Destination: argov1alpha1.ApplicationDestination{Name: "my-cluster", Namespace: "namespace"}, + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Source: &v1alpha1.ApplicationSource{ + Directory: &v1alpha1.ApplicationSourceDirectory{ + Jsonnet: v1alpha1.ApplicationSourceJsonnet{}, + }, + }, + }, + }, }, - } - - initObjs := []crtclient.Object{&app, &appSet} - - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).Build() - secret := &corev1.Secret{ + }, + desiredApps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Source: &v1alpha1.ApplicationSource{ + Directory: &v1alpha1.ApplicationSourceDirectory{ + Jsonnet: v1alpha1.ApplicationSourceJsonnet{}, + }, + }, + }, + }, + }, + expected: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + ResourceVersion: "1", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Source: &v1alpha1.ApplicationSource{ + // Directory and jsonnet block are removed + }, + }, + }, + }, + }, { + // 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: "my-secret", + Name: "name", Namespace: "namespace", - Labels: map[string]string{ - generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, + }, + 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", + }, + }, }, }, - Data: map[string][]byte{ - // Since this test requires the cluster to be an invalid destination, we - // always return a cluster named 'my-cluster2' (different from app 'my-cluster', above) - "name": []byte("mycluster2"), - "server": []byte("https://kubernetes.default.svc"), - "config": []byte("{\"username\":\"foo\",\"password\":\"foo\"}"), - }, - } - - objects := append([]runtime.Object{}, secret) - kubeclientset := kubefake.NewSimpleClientset(objects...) - - r := ApplicationSetReconciler{ - Client: client, - Scheme: scheme, - Recorder: record.NewFakeRecorder(10), - KubeClientset: kubeclientset, - } - //settingsMgr := settings.NewSettingsManager(context.TODO(), kubeclientset, "namespace") - //argoDB := db.NewDB("namespace", settingsMgr, r.KubeClientset) - //clusterList, err := argoDB.ListClusters(context.Background()) - clusterList, err := utils.ListClusters(context.Background(), kubeclientset, "namespace") - assert.NoError(t, err, "Unexpected error") - - appLog := log.WithFields(log.Fields{"app": app.Name, "appSet": ""}) - - appInputParam := app.DeepCopy() - - err = r.removeFinalizerOnInvalidDestination(context.Background(), appSet, appInputParam, clusterList, appLog) - assert.NoError(t, err, "Unexpected error") - - retrievedApp := argov1alpha1.Application{} - err = client.Get(context.Background(), crtclient.ObjectKeyFromObject(&app), &retrievedApp) - assert.NoError(t, err, "Unexpected error") - - // App on the cluster should have the expected finalizers - assert.ElementsMatch(t, c.expectedFinalizers, retrievedApp.Finalizers) - - // App object passed in as a parameter should have the expected finaliers - assert.ElementsMatch(t, c.expectedFinalizers, appInputParam.Finalizers) - - bytes, _ := json.MarshalIndent(retrievedApp, "", " ") - t.Log("Contents of app after call:", string(bytes)) - - }) - } -} - -func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) { - - scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) - assert.Nil(t, err) - - err = argov1alpha1.AddToScheme(scheme) - assert.Nil(t, err) - - for _, c := range []struct { - // name is human-readable test name - name string - destinationField argov1alpha1.ApplicationDestination - expectFinalizerRemoved bool - }{ - { - name: "invalid cluster: empty destination", - destinationField: argov1alpha1.ApplicationDestination{ - Namespace: "namespace", - }, - expectFinalizerRemoved: true, - }, - { - name: "invalid cluster: invalid server url", - destinationField: argov1alpha1.ApplicationDestination{ - Namespace: "namespace", - Server: "https://1.2.3.4", - }, - expectFinalizerRemoved: true, - }, - { - name: "invalid cluster: invalid cluster name", - destinationField: argov1alpha1.ApplicationDestination{ - Namespace: "namespace", - Name: "invalid-cluster", - }, - expectFinalizerRemoved: true, - }, - { - name: "invalid cluster by both valid", - destinationField: argov1alpha1.ApplicationDestination{ - Namespace: "namespace", - Name: "mycluster2", - Server: "https://kubernetes.default.svc", - }, - expectFinalizerRemoved: true, - }, - { - name: "invalid cluster by both invalid", - destinationField: argov1alpha1.ApplicationDestination{ - Namespace: "namespace", - Name: "mycluster3", - Server: "https://4.5.6.7", - }, - expectFinalizerRemoved: true, - }, - { - name: "valid cluster by name", - destinationField: argov1alpha1.ApplicationDestination{ - Namespace: "namespace", - Name: "mycluster2", - }, - expectFinalizerRemoved: false, - }, - { - name: "valid cluster by server", - destinationField: argov1alpha1.ApplicationDestination{ - Namespace: "namespace", - Server: "https://kubernetes.default.svc", - }, - expectFinalizerRemoved: false, - }, - } { - - t.Run(c.name, func(t *testing.T) { - - appSet := argov1alpha1.ApplicationSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "name", - Namespace: "namespace", - }, - Spec: argov1alpha1.ApplicationSetSpec{ - Template: argov1alpha1.ApplicationSetTemplate{ - Spec: argov1alpha1.ApplicationSpec{ - Project: "project", - }, - }, - }, - } - - app := argov1alpha1.Application{ - ObjectMeta: metav1.ObjectMeta{ - Name: "app1", - Finalizers: []string{argov1alpha1.ResourcesFinalizerName}, - }, - Spec: argov1alpha1.ApplicationSpec{ - Project: "project", - Source: &argov1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"}, - Destination: c.destinationField, - }, - } - - initObjs := []crtclient.Object{&app, &appSet} - - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).Build() - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-secret", - Namespace: "namespace", - Labels: map[string]string{ - generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, - }, - }, - Data: map[string][]byte{ - // Since this test requires the cluster to be an invalid destination, we - // always return a cluster named 'my-cluster2' (different from app 'my-cluster', above) - "name": []byte("mycluster2"), - "server": []byte("https://kubernetes.default.svc"), - "config": []byte("{\"username\":\"foo\",\"password\":\"foo\"}"), - }, - } - - objects := append([]runtime.Object{}, secret) - kubeclientset := kubefake.NewSimpleClientset(objects...) - - r := ApplicationSetReconciler{ - Client: client, - Scheme: scheme, - Recorder: record.NewFakeRecorder(10), - KubeClientset: kubeclientset, - } - // settingsMgr := settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd") - // argoDB := db.NewDB("argocd", settingsMgr, r.KubeClientset) - // clusterList, err := argoDB.ListClusters(context.Background()) - clusterList, err := utils.ListClusters(context.Background(), kubeclientset, "namespace") - assert.NoError(t, err, "Unexpected error") - - appLog := log.WithFields(log.Fields{"app": app.Name, "appSet": ""}) - - appInputParam := app.DeepCopy() - - err = r.removeFinalizerOnInvalidDestination(context.Background(), appSet, appInputParam, clusterList, appLog) - assert.NoError(t, err, "Unexpected error") - - retrievedApp := argov1alpha1.Application{} - err = client.Get(context.Background(), crtclient.ObjectKeyFromObject(&app), &retrievedApp) - assert.NoError(t, err, "Unexpected error") - - finalizerRemoved := len(retrievedApp.Finalizers) == 0 - - assert.True(t, c.expectFinalizerRemoved == finalizerRemoved) - - bytes, _ := json.MarshalIndent(retrievedApp, "", " ") - t.Log("Contents of app after call:", string(bytes)) - - }) - } -} - -func TestCreateApplications(t *testing.T) { - - scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) - assert.Nil(t, err) - - err = argov1alpha1.AddToScheme(scheme) - assert.Nil(t, err) - - for _, c := range []struct { - appSet argov1alpha1.ApplicationSet - existsApps []argov1alpha1.Application - apps []argov1alpha1.Application - expected []argov1alpha1.Application - }{ - { - appSet: argov1alpha1.ApplicationSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "name", - Namespace: "namespace", + }, + 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", + }, + }, }, }, - existsApps: nil, - apps: []argov1alpha1.Application{ + 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: []argov1alpha1.Application{ + expected: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ Kind: "Application", @@ -1184,26 +1064,52 @@ func TestCreateApplications(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app1", Namespace: "namespace", - ResourceVersion: "1", + 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"}, + }, + }, + }, }, }, }, - }, - { - appSet: argov1alpha1.ApplicationSet{ + }, { + // 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: argov1alpha1.ApplicationSetSpec{ - Template: argov1alpha1.ApplicationSetTemplate{ - Spec: argov1alpha1.ApplicationSpec{ + 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", + }, + }, + }, }, }, }, }, - existsApps: []argov1alpha1.Application{ + existingApps: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ Kind: "Application", @@ -1214,53 +1120,96 @@ func TestCreateApplications(t *testing.T) { Namespace: "namespace", ResourceVersion: "2", }, - Spec: argov1alpha1.ApplicationSpec{ - Project: "test", + 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"}, + }, + }, + }, + }, }, }, }, - apps: []argov1alpha1.Application{ + desiredApps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Spec: argov1alpha1.ApplicationSpec{ + 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: []argov1alpha1.Application{ + expected: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ Kind: "Application", APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ - Name: "app1", - Namespace: "namespace", + Name: "app1", + Namespace: "namespace", + // This should not be updated, because reconciliation shouldn't modify the App. ResourceVersion: "2", }, - Spec: argov1alpha1.ApplicationSpec{ - Project: "test", + 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"}, + }, + }, + }, + }, }, }, }, - }, - { - appSet: argov1alpha1.ApplicationSet{ + }, { + 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: argov1alpha1.ApplicationSetSpec{ - Template: argov1alpha1.ApplicationSetTemplate{ - Spec: argov1alpha1.ApplicationSpec{ + 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", + }, + }, + }, }, }, }, }, - existsApps: []argov1alpha1.Application{ + existingApps: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ Kind: "Application", @@ -1271,439 +1220,336 @@ func TestCreateApplications(t *testing.T) { Namespace: "namespace", ResourceVersion: "2", }, - Spec: argov1alpha1.ApplicationSpec{ - Project: "test", + 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"}, + }, + }, + }, + }, }, }, }, - apps: []argov1alpha1.Application{ + desiredApps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ - Name: "app2", + Name: "app1", }, - Spec: argov1alpha1.ApplicationSpec{ + 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: []argov1alpha1.Application{ + expected: []v1alpha1.Application{ { TypeMeta: metav1.TypeMeta{ Kind: "Application", APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ - Name: "app2", + Name: "app1", Namespace: "namespace", - ResourceVersion: "1", + ResourceVersion: "3", }, - Spec: argov1alpha1.ApplicationSpec{ + 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. + }, + }, + }, }, }, }, }, } { - initObjs := []crtclient.Object{&c.appSet} - for _, a := range c.existsApps { - err = controllerutil.SetControllerReference(&c.appSet, &a, scheme) - assert.Nil(t, err) - initObjs = append(initObjs, &a) - } - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).Build() + t.Run(c.name, func(t *testing.T) { - r := ApplicationSetReconciler{ - Client: client, - Scheme: scheme, - Recorder: record.NewFakeRecorder(len(initObjs) + len(c.expected)), - } + initObjs := []crtclient.Object{&c.appSet} - err = r.createInCluster(context.TODO(), c.appSet, c.apps) - assert.Nil(t, err) + for _, a := range c.existingApps { + err = controllerutil.SetControllerReference(&c.appSet, &a, scheme) + assert.Nil(t, err) + initObjs = append(initObjs, &a) + } - for _, obj := range c.expected { - got := &argov1alpha1.Application{} - _ = client.Get(context.Background(), crtclient.ObjectKey{ - Namespace: obj.Namespace, - Name: obj.Name, - }, got) + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() - err = controllerutil.SetControllerReference(&c.appSet, &obj, r.Scheme) - assert.Nil(t, err) + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Recorder: record.NewFakeRecorder(len(initObjs) + len(c.expected)), + Cache: &fakeCache{}, + } - assert.Equal(t, obj, *got) - } - } + 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{} + _ = client.Get(context.Background(), crtclient.ObjectKey{ + Namespace: obj.Namespace, + Name: obj.Name, + }, got) + err = controllerutil.SetControllerReference(&c.appSet, &obj, r.Scheme) + assert.Equal(t, obj, *got) + } + }) + } } -func TestDeleteInCluster(t *testing.T) { +func TestRemoveFinalizerOnInvalidDestination_FinalizerTypes(t *testing.T) { scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) + err := v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - err = argov1alpha1.AddToScheme(scheme) + + err = v1alpha1.AddToScheme(scheme) assert.Nil(t, err) for _, c := range []struct { - // appSet is the application set on which the delete function is called - appSet argov1alpha1.ApplicationSet - // existingApps is the current state of Applications on the cluster - existingApps []argov1alpha1.Application - // desireApps is the apps generated by the generator that we wish to keep alive - desiredApps []argov1alpha1.Application - // expected is the list of applications that we expect to exist after calling delete - expected []argov1alpha1.Application - // notExpected is the list of applications that we expect not to exist after calling delete - notExpected []argov1alpha1.Application + // name is human-readable test name + name string + existingFinalizers []string + expectedFinalizers []string }{ { - appSet: argov1alpha1.ApplicationSet{ + name: "no finalizers", + existingFinalizers: []string{}, + expectedFinalizers: nil, + }, + { + name: "contains only argo finalizer", + existingFinalizers: []string{v1alpha1.ResourcesFinalizerName}, + expectedFinalizers: nil, + }, + { + name: "contains only non-argo finalizer", + existingFinalizers: []string{"non-argo-finalizer"}, + expectedFinalizers: []string{"non-argo-finalizer"}, + }, + { + name: "contains both argo and non-argo finalizer", + existingFinalizers: []string{"non-argo-finalizer", v1alpha1.ResourcesFinalizerName}, + expectedFinalizers: []string{"non-argo-finalizer"}, + }, + } { + t.Run(c.name, func(t *testing.T) { + + appSet := v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Template: argov1alpha1.ApplicationSetTemplate{ - Spec: argov1alpha1.ApplicationSpec{ + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ Project: "project", }, }, }, - }, - existingApps: []argov1alpha1.Application{ - { - TypeMeta: metav1.TypeMeta{ - Kind: "Application", - APIVersion: "argoproj.io/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "delete", - Namespace: "namespace", - ResourceVersion: "2", - }, - Spec: argov1alpha1.ApplicationSpec{ - Project: "project", - }, - }, - { - TypeMeta: metav1.TypeMeta{ - Kind: "Application", - APIVersion: "argoproj.io/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "keep", - Namespace: "namespace", - ResourceVersion: "2", - }, - Spec: argov1alpha1.ApplicationSpec{ - Project: "project", - }, + } + + app := v1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Finalizers: c.existingFinalizers, }, - }, - desiredApps: []argov1alpha1.Application{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "keep", - }, - Spec: argov1alpha1.ApplicationSpec{ - Project: "project", - }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Source: &v1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"}, + // Destination is always invalid, for this test: + Destination: v1alpha1.ApplicationDestination{Name: "my-cluster", Namespace: "namespace"}, }, - }, - expected: []argov1alpha1.Application{ - { - TypeMeta: metav1.TypeMeta{ - Kind: "Application", - APIVersion: "argoproj.io/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "keep", - Namespace: "namespace", - ResourceVersion: "2", - }, - Spec: argov1alpha1.ApplicationSpec{ - Project: "project", + } + + initObjs := []crtclient.Object{&app, &appSet} + + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-secret", + Namespace: "namespace", + Labels: map[string]string{ + generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, }, }, - }, - notExpected: []argov1alpha1.Application{ - { - TypeMeta: metav1.TypeMeta{ - Kind: "Application", - APIVersion: "argoproj.io/v1alpha1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "delete", - Namespace: "namespace", - ResourceVersion: "1", - }, - Spec: argov1alpha1.ApplicationSpec{ - Project: "project", - }, + Data: map[string][]byte{ + // Since this test requires the cluster to be an invalid destination, we + // always return a cluster named 'my-cluster2' (different from app 'my-cluster', above) + "name": []byte("mycluster2"), + "server": []byte("https://kubernetes.default.svc"), + "config": []byte("{\"username\":\"foo\",\"password\":\"foo\"}"), }, - }, - }, - } { - initObjs := []crtclient.Object{&c.appSet} - for _, a := range c.existingApps { - temp := a - err = controllerutil.SetControllerReference(&c.appSet, &temp, scheme) - assert.Nil(t, err) - initObjs = append(initObjs, &temp) - } - - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).Build() + } - r := ApplicationSetReconciler{ - Client: client, - Scheme: scheme, - Recorder: record.NewFakeRecorder(len(initObjs) + len(c.expected)), - KubeClientset: kubefake.NewSimpleClientset(), - } + objects := append([]runtime.Object{}, secret) + kubeclientset := kubefake.NewSimpleClientset(objects...) - err = r.deleteInCluster(context.TODO(), c.appSet, c.desiredApps) - assert.Nil(t, err) + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Recorder: record.NewFakeRecorder(10), + KubeClientset: kubeclientset, + Cache: &fakeCache{}, + } + //settingsMgr := settings.NewSettingsManager(context.TODO(), kubeclientset, "namespace") + //argoDB := db.NewDB("namespace", settingsMgr, r.KubeClientset) + //clusterList, err := argoDB.ListClusters(context.Background()) + clusterList, err := utils.ListClusters(context.Background(), kubeclientset, "namespace") + assert.NoError(t, err, "Unexpected error") - // For each of the expected objects, verify they exist on the cluster - for _, obj := range c.expected { - got := &argov1alpha1.Application{} - _ = client.Get(context.Background(), crtclient.ObjectKey{ - Namespace: obj.Namespace, - Name: obj.Name, - }, got) + appLog := log.WithFields(log.Fields{"app": app.Name, "appSet": ""}) - err = controllerutil.SetControllerReference(&c.appSet, &obj, r.Scheme) - assert.Nil(t, err) + appInputParam := app.DeepCopy() - assert.Equal(t, obj, *got) - } + err = r.removeFinalizerOnInvalidDestination(context.Background(), appSet, appInputParam, clusterList, appLog) + assert.NoError(t, err, "Unexpected error") - // Verify each of the unexpected objs cannot be found - for _, obj := range c.notExpected { - got := &argov1alpha1.Application{} - err := client.Get(context.Background(), crtclient.ObjectKey{ - Namespace: obj.Namespace, - Name: obj.Name, - }, got) + retrievedApp := v1alpha1.Application{} + err = client.Get(context.Background(), crtclient.ObjectKeyFromObject(&app), &retrievedApp) + assert.NoError(t, err, "Unexpected error") - assert.EqualError(t, err, fmt.Sprintf("applications.argoproj.io \"%s\" not found", obj.Name)) - } - } -} + // App on the cluster should have the expected finalizers + assert.ElementsMatch(t, c.expectedFinalizers, retrievedApp.Finalizers) -func TestGetMinRequeueAfter(t *testing.T) { - scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) - assert.Nil(t, err) - err = argov1alpha1.AddToScheme(scheme) - assert.Nil(t, err) + // App object passed in as a parameter should have the expected finaliers + assert.ElementsMatch(t, c.expectedFinalizers, appInputParam.Finalizers) - client := fake.NewClientBuilder().WithScheme(scheme).Build() + bytes, _ := json.MarshalIndent(retrievedApp, "", " ") + t.Log("Contents of app after call:", string(bytes)) - generator := argov1alpha1.ApplicationSetGenerator{ - List: &argov1alpha1.ListGenerator{}, - Git: &argov1alpha1.GitGenerator{}, - Clusters: &argov1alpha1.ClusterGenerator{}, + }) } +} - generatorMock0 := generatorMock{} - generatorMock0.On("GetRequeueAfter", &generator). - Return(generators.NoRequeueAfter) - - generatorMock1 := generatorMock{} - generatorMock1.On("GetRequeueAfter", &generator). - Return(time.Duration(1) * time.Second) +func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) { - generatorMock10 := generatorMock{} - generatorMock10.On("GetRequeueAfter", &generator). - Return(time.Duration(10) * time.Second) + scheme := runtime.NewScheme() + err := v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) - r := ApplicationSetReconciler{ - Client: client, - Scheme: scheme, - Recorder: record.NewFakeRecorder(0), - Generators: map[string]generators.Generator{ - "List": &generatorMock10, - "Git": &generatorMock1, - "Clusters": &generatorMock1, - }, - } + err = v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) - got := r.getMinRequeueAfter(&argov1alpha1.ApplicationSet{ - Spec: argov1alpha1.ApplicationSetSpec{ - Generators: []argov1alpha1.ApplicationSetGenerator{generator}, - }, - }) - - assert.Equal(t, time.Duration(1)*time.Second, got) -} - -func TestValidateGeneratedApplications(t *testing.T) { - - scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) - assert.Nil(t, err) - - err = argov1alpha1.AddToScheme(scheme) - assert.Nil(t, err) - - client := fake.NewClientBuilder().WithScheme(scheme).Build() - - // Valid cluster - myCluster := argov1alpha1.Cluster{ - Server: "https://kubernetes.default.svc", - Name: "my-cluster", - } - - // Valid project - myProject := &argov1alpha1.AppProject{ - ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "namespace"}, - Spec: argov1alpha1.AppProjectSpec{ - SourceRepos: []string{"*"}, - Destinations: []argov1alpha1.ApplicationDestination{ - { - Namespace: "*", - Server: "*", - }, + for _, c := range []struct { + // name is human-readable test name + name string + destinationField v1alpha1.ApplicationDestination + expectFinalizerRemoved bool + }{ + { + name: "invalid cluster: empty destination", + destinationField: v1alpha1.ApplicationDestination{ + Namespace: "namespace", }, - ClusterResourceWhitelist: []metav1.GroupKind{ - { - Group: "*", - Kind: "*", - }, + expectFinalizerRemoved: true, + }, + { + name: "invalid cluster: invalid server url", + destinationField: v1alpha1.ApplicationDestination{ + Namespace: "namespace", + Server: "https://1.2.3.4", }, + expectFinalizerRemoved: true, }, - } - - // Test a subset of the validations that 'validateGeneratedApplications' performs - for _, cc := range []struct { - name string - apps []argov1alpha1.Application - expectedErrors []string - validationErrors map[int]error - }{ { - name: "valid app should return true", - apps: []argov1alpha1.Application{ - { - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{}, - Spec: argov1alpha1.ApplicationSpec{ - Project: "default", - Source: &argov1alpha1.ApplicationSource{ - RepoURL: "https://url", - Path: "/", - TargetRevision: "HEAD", - }, - Destination: argov1alpha1.ApplicationDestination{ - Namespace: "namespace", - Name: "my-cluster", - }, - }, - }, + name: "invalid cluster: invalid cluster name", + destinationField: v1alpha1.ApplicationDestination{ + Namespace: "namespace", + Name: "invalid-cluster", }, - expectedErrors: []string{}, - validationErrors: map[int]error{}, + expectFinalizerRemoved: true, }, { - name: "can't have both name and server defined", - apps: []argov1alpha1.Application{ - { - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{}, - Spec: argov1alpha1.ApplicationSpec{ - Project: "default", - Source: &argov1alpha1.ApplicationSource{ - RepoURL: "https://url", - Path: "/", - TargetRevision: "HEAD", - }, - Destination: argov1alpha1.ApplicationDestination{ - Namespace: "namespace", - Server: "my-server", - Name: "my-cluster", - }, - }, - }, + name: "invalid cluster by both valid", + destinationField: v1alpha1.ApplicationDestination{ + Namespace: "namespace", + Name: "mycluster2", + Server: "https://kubernetes.default.svc", }, - expectedErrors: []string{"application destination can't have both name and server defined"}, - validationErrors: map[int]error{0: fmt.Errorf("application destination spec is invalid: application destination can't have both name and server defined: my-cluster my-server")}, + expectFinalizerRemoved: true, }, { - name: "project mismatch should return error", - apps: []argov1alpha1.Application{ - { - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{}, - Spec: argov1alpha1.ApplicationSpec{ - Project: "DOES-NOT-EXIST", - Source: &argov1alpha1.ApplicationSource{ - RepoURL: "https://url", - Path: "/", - TargetRevision: "HEAD", - }, - Destination: argov1alpha1.ApplicationDestination{ - Namespace: "namespace", - Name: "my-cluster", - }, - }, - }, + name: "invalid cluster by both invalid", + destinationField: v1alpha1.ApplicationDestination{ + Namespace: "namespace", + Name: "mycluster3", + Server: "https://4.5.6.7", }, - expectedErrors: []string{"application references project DOES-NOT-EXIST which does not exist"}, - validationErrors: map[int]error{0: fmt.Errorf("application references project DOES-NOT-EXIST which does not exist")}, + expectFinalizerRemoved: true, }, { - name: "valid app should return true", - apps: []argov1alpha1.Application{ - { - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{}, - Spec: argov1alpha1.ApplicationSpec{ - Project: "default", - Source: &argov1alpha1.ApplicationSource{ - RepoURL: "https://url", - Path: "/", - TargetRevision: "HEAD", - }, - Destination: argov1alpha1.ApplicationDestination{ - Namespace: "namespace", - Name: "my-cluster", - }, - }, - }, + name: "valid cluster by name", + destinationField: v1alpha1.ApplicationDestination{ + Namespace: "namespace", + Name: "mycluster2", }, - expectedErrors: []string{}, - validationErrors: map[int]error{}, + expectFinalizerRemoved: false, }, { - name: "cluster should match", - apps: []argov1alpha1.Application{ - { - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{}, - Spec: argov1alpha1.ApplicationSpec{ - Project: "default", - Source: &argov1alpha1.ApplicationSource{ - RepoURL: "https://url", - Path: "/", - TargetRevision: "HEAD", - }, - Destination: argov1alpha1.ApplicationDestination{ - Namespace: "namespace", - Name: "nonexistent-cluster", - }, - }, - }, + name: "valid cluster by server", + destinationField: v1alpha1.ApplicationDestination{ + Namespace: "namespace", + Server: "https://kubernetes.default.svc", }, - expectedErrors: []string{"there are no clusters with this name: nonexistent-cluster"}, - validationErrors: map[int]error{0: fmt.Errorf("application destination spec is invalid: unable to find destination server: there are no clusters with this name: nonexistent-cluster")}, + expectFinalizerRemoved: false, }, } { - t.Run(cc.name, func(t *testing.T) { + t.Run(c.name, func(t *testing.T) { + appSet := v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + } + + app := v1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Finalizers: []string{v1alpha1.ResourcesFinalizerName}, + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Source: &v1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"}, + Destination: c.destinationField, + }, + } + + initObjs := []crtclient.Object{&app, &appSet} + + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "my-secret", @@ -1713,110 +1559,1221 @@ func TestValidateGeneratedApplications(t *testing.T) { }, }, Data: map[string][]byte{ - "name": []byte("my-cluster"), + // Since this test requires the cluster to be an invalid destination, we + // always return a cluster named 'my-cluster2' (different from app 'my-cluster', above) + "name": []byte("mycluster2"), "server": []byte("https://kubernetes.default.svc"), "config": []byte("{\"username\":\"foo\",\"password\":\"foo\"}"), }, } - objects := append([]runtime.Object{}, secret) - kubeclientset := kubefake.NewSimpleClientset(objects...) + objects := append([]runtime.Object{}, secret) + kubeclientset := kubefake.NewSimpleClientset(objects...) + + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Recorder: record.NewFakeRecorder(10), + KubeClientset: kubeclientset, + Cache: &fakeCache{}, + } + // settingsMgr := settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd") + // argoDB := db.NewDB("argocd", settingsMgr, r.KubeClientset) + // clusterList, err := argoDB.ListClusters(context.Background()) + clusterList, err := utils.ListClusters(context.Background(), kubeclientset, "namespace") + assert.NoError(t, err, "Unexpected error") + + appLog := log.WithFields(log.Fields{"app": app.Name, "appSet": ""}) + + appInputParam := app.DeepCopy() + + err = r.removeFinalizerOnInvalidDestination(context.Background(), appSet, appInputParam, clusterList, appLog) + assert.NoError(t, err, "Unexpected error") + + retrievedApp := v1alpha1.Application{} + err = client.Get(context.Background(), crtclient.ObjectKeyFromObject(&app), &retrievedApp) + assert.NoError(t, err, "Unexpected error") + + finalizerRemoved := len(retrievedApp.Finalizers) == 0 + + assert.True(t, c.expectFinalizerRemoved == finalizerRemoved) + + bytes, _ := json.MarshalIndent(retrievedApp, "", " ") + t.Log("Contents of app after call:", string(bytes)) + + }) + } +} + +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() + err := v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + + err = v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + + testCases := []struct { + name string + appSet v1alpha1.ApplicationSet + existsApps []v1alpha1.Application + apps []v1alpha1.Application + expected []v1alpha1.Application + }{ + { + name: "no existing apps", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + }, + }, + existsApps: nil, + apps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + }, + }, + }, + expected: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + ResourceVersion: "1", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "default", + }, + }, + }, + }, + { + name: "existing apps", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + }, + existsApps: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + ResourceVersion: "2", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "test", + }, + }, + }, + apps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + expected: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + ResourceVersion: "2", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "test", + }, + }, + }, + }, + { + name: "existing apps with different project", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + }, + existsApps: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + ResourceVersion: "2", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "test", + }, + }, + }, + apps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app2", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + expected: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app2", + Namespace: "namespace", + ResourceVersion: "1", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + }, + } + + for _, c := range testCases { + t.Run(c.name, func(t *testing.T) { + initObjs := []crtclient.Object{&c.appSet} + for _, a := range c.existsApps { + err = controllerutil.SetControllerReference(&c.appSet, &a, scheme) + assert.Nil(t, err) + initObjs = append(initObjs, &a) + } + + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() + + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Recorder: record.NewFakeRecorder(len(initObjs) + len(c.expected)), + Cache: &fakeCache{}, + } + + err = r.createInCluster(context.TODO(), log.NewEntry(log.StandardLogger()), c.appSet, c.apps) + assert.Nil(t, err) + + for _, obj := range c.expected { + got := &v1alpha1.Application{} + _ = client.Get(context.Background(), crtclient.ObjectKey{ + Namespace: obj.Namespace, + Name: obj.Name, + }, got) + + err = controllerutil.SetControllerReference(&c.appSet, &obj, r.Scheme) + assert.Nil(t, err) + + assert.Equal(t, obj, *got) + } + }) + } +} + +func TestDeleteInCluster(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 { + // appSet is the application set on which the delete function is called + appSet v1alpha1.ApplicationSet + // existingApps is the current state of Applications on the cluster + existingApps []v1alpha1.Application + // desireApps is the apps generated by the generator that we wish to keep alive + desiredApps []v1alpha1.Application + // expected is the list of applications that we expect to exist after calling delete + expected []v1alpha1.Application + // notExpected is the list of applications that we expect not to exist after calling delete + notExpected []v1alpha1.Application + }{ + { + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + }, + existingApps: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "delete", + Namespace: "namespace", + ResourceVersion: "2", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + { + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "keep", + Namespace: "namespace", + ResourceVersion: "2", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + desiredApps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "keep", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + expected: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "keep", + Namespace: "namespace", + ResourceVersion: "2", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + notExpected: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "delete", + Namespace: "namespace", + ResourceVersion: "1", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + }, + } { + initObjs := []crtclient.Object{&c.appSet} + for _, a := range c.existingApps { + temp := a + err = controllerutil.SetControllerReference(&c.appSet, &temp, scheme) + assert.Nil(t, err) + initObjs = append(initObjs, &temp) + } + + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() + + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Recorder: record.NewFakeRecorder(len(initObjs) + len(c.expected)), + KubeClientset: kubefake.NewSimpleClientset(), + } + + 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 + for _, obj := range c.expected { + got := &v1alpha1.Application{} + _ = client.Get(context.Background(), crtclient.ObjectKey{ + Namespace: obj.Namespace, + Name: obj.Name, + }, got) + + err = controllerutil.SetControllerReference(&c.appSet, &obj, r.Scheme) + assert.Nil(t, err) + + assert.Equal(t, obj, *got) + } + + // Verify each of the unexpected objs cannot be found + for _, obj := range c.notExpected { + got := &v1alpha1.Application{} + err := client.Get(context.Background(), crtclient.ObjectKey{ + Namespace: obj.Namespace, + Name: obj.Name, + }, got) + + assert.EqualError(t, err, fmt.Sprintf("applications.argoproj.io \"%s\" not found", obj.Name)) + } + } +} + +func TestGetMinRequeueAfter(t *testing.T) { + scheme := runtime.NewScheme() + err := v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + err = v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + + client := fake.NewClientBuilder().WithScheme(scheme).Build() + + generator := v1alpha1.ApplicationSetGenerator{ + List: &v1alpha1.ListGenerator{}, + Git: &v1alpha1.GitGenerator{}, + Clusters: &v1alpha1.ClusterGenerator{}, + } + + generatorMock0 := generatorMock{} + generatorMock0.On("GetRequeueAfter", &generator). + Return(generators.NoRequeueAfter) + + generatorMock1 := generatorMock{} + generatorMock1.On("GetRequeueAfter", &generator). + Return(time.Duration(1) * time.Second) + + generatorMock10 := generatorMock{} + generatorMock10.On("GetRequeueAfter", &generator). + Return(time.Duration(10) * time.Second) + + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Recorder: record.NewFakeRecorder(0), + Cache: &fakeCache{}, + Generators: map[string]generators.Generator{ + "List": &generatorMock10, + "Git": &generatorMock1, + "Clusters": &generatorMock1, + }, + } + + got := r.getMinRequeueAfter(&v1alpha1.ApplicationSet{ + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{generator}, + }, + }) + + assert.Equal(t, time.Duration(1)*time.Second, got) +} + +func TestValidateGeneratedApplications(t *testing.T) { + + scheme := runtime.NewScheme() + err := v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + + err = v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + + client := fake.NewClientBuilder().WithScheme(scheme).Build() + + // Valid cluster + myCluster := v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Name: "my-cluster", + } + + // Valid project + myProject := &v1alpha1.AppProject{ + ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "namespace"}, + Spec: v1alpha1.AppProjectSpec{ + SourceRepos: []string{"*"}, + Destinations: []v1alpha1.ApplicationDestination{ + { + Namespace: "*", + Server: "*", + }, + }, + ClusterResourceWhitelist: []metav1.GroupKind{ + { + Group: "*", + Kind: "*", + }, + }, + }, + } + + // Test a subset of the validations that 'validateGeneratedApplications' performs + for _, cc := range []struct { + name string + apps []v1alpha1.Application + expectedErrors []string + validationErrors map[int]error + }{ + { + name: "valid app should return true", + apps: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: v1alpha1.ApplicationSpec{ + Project: "default", + Source: &v1alpha1.ApplicationSource{ + RepoURL: "https://url", + Path: "/", + TargetRevision: "HEAD", + }, + Destination: v1alpha1.ApplicationDestination{ + Namespace: "namespace", + Name: "my-cluster", + }, + }, + }, + }, + expectedErrors: []string{}, + validationErrors: map[int]error{}, + }, + { + name: "can't have both name and server defined", + apps: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: v1alpha1.ApplicationSpec{ + Project: "default", + Source: &v1alpha1.ApplicationSource{ + RepoURL: "https://url", + Path: "/", + TargetRevision: "HEAD", + }, + Destination: v1alpha1.ApplicationDestination{ + Namespace: "namespace", + Server: "my-server", + Name: "my-cluster", + }, + }, + }, + }, + expectedErrors: []string{"application destination can't have both name and server defined"}, + validationErrors: map[int]error{0: fmt.Errorf("application destination spec is invalid: application destination can't have both name and server defined: my-cluster my-server")}, + }, + { + name: "project mismatch should return error", + apps: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: v1alpha1.ApplicationSpec{ + Project: "DOES-NOT-EXIST", + Source: &v1alpha1.ApplicationSource{ + RepoURL: "https://url", + Path: "/", + TargetRevision: "HEAD", + }, + Destination: v1alpha1.ApplicationDestination{ + Namespace: "namespace", + Name: "my-cluster", + }, + }, + }, + }, + expectedErrors: []string{"application references project DOES-NOT-EXIST which does not exist"}, + validationErrors: map[int]error{0: fmt.Errorf("application references project DOES-NOT-EXIST which does not exist")}, + }, + { + name: "valid app should return true", + apps: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: v1alpha1.ApplicationSpec{ + Project: "default", + Source: &v1alpha1.ApplicationSource{ + RepoURL: "https://url", + Path: "/", + TargetRevision: "HEAD", + }, + Destination: v1alpha1.ApplicationDestination{ + Namespace: "namespace", + Name: "my-cluster", + }, + }, + }, + }, + expectedErrors: []string{}, + validationErrors: map[int]error{}, + }, + { + name: "cluster should match", + apps: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: v1alpha1.ApplicationSpec{ + Project: "default", + Source: &v1alpha1.ApplicationSource{ + RepoURL: "https://url", + Path: "/", + TargetRevision: "HEAD", + }, + Destination: v1alpha1.ApplicationDestination{ + Namespace: "namespace", + Name: "nonexistent-cluster", + }, + }, + }, + }, + expectedErrors: []string{"there are no clusters with this name: nonexistent-cluster"}, + validationErrors: map[int]error{0: fmt.Errorf("application destination spec is invalid: unable to find destination server: there are no clusters with this name: nonexistent-cluster")}, + }, + } { + + t.Run(cc.name, func(t *testing.T) { + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-secret", + Namespace: "namespace", + Labels: map[string]string{ + generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, + }, + }, + Data: map[string][]byte{ + "name": []byte("my-cluster"), + "server": []byte("https://kubernetes.default.svc"), + "config": []byte("{\"username\":\"foo\",\"password\":\"foo\"}"), + }, + } + + objects := append([]runtime.Object{}, secret) + kubeclientset := kubefake.NewSimpleClientset(objects...) + + argoDBMock := dbmocks.ArgoDB{} + argoDBMock.On("GetCluster", mock.Anything, "https://kubernetes.default.svc").Return(&myCluster, nil) + argoDBMock.On("ListClusters", mock.Anything).Return(&v1alpha1.ClusterList{Items: []v1alpha1.Cluster{ + myCluster, + }}, nil) + + argoObjs := []runtime.Object{myProject} + for _, app := range cc.apps { + argoObjs = append(argoObjs, &app) + } + + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Recorder: record.NewFakeRecorder(1), + Cache: &fakeCache{}, + Generators: map[string]generators.Generator{}, + ArgoDB: &argoDBMock, + ArgoCDNamespace: "namespace", + ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), + KubeClientset: kubeclientset, + } + + appSetInfo := v1alpha1.ApplicationSet{} + + validationErrors, _ := r.validateGeneratedApplications(context.TODO(), cc.apps, appSetInfo) + var errorMessages []string + for _, v := range validationErrors { + errorMessages = append(errorMessages, v.Error()) + } + + if len(errorMessages) == 0 { + assert.Equal(t, len(cc.expectedErrors), 0, "Expected errors but none were seen") + } else { + // An error was returned: it should be expected + matched := false + for _, expectedErr := range cc.expectedErrors { + foundMatch := strings.Contains(strings.Join(errorMessages, ";"), expectedErr) + assert.True(t, foundMatch, "Unble to locate expected error: %s", cc.expectedErrors) + matched = matched || foundMatch + } + assert.True(t, matched, "An unexpected error occurrred: %v", err) + // validation message was returned: it should be expected + matched = false + foundMatch := reflect.DeepEqual(validationErrors, cc.validationErrors) + var message string + for _, v := range validationErrors { + message = v.Error() + break + } + assert.True(t, foundMatch, "Unble to locate validation message: %s", message) + matched = matched || foundMatch + assert.True(t, matched, "An unexpected error occurrred: %v", err) + } + }) + } +} + +func TestReconcilerValidationProjectErrorBehaviour(t *testing.T) { + + scheme := runtime.NewScheme() + err := v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + err = v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + + project := v1alpha1.AppProject{ + ObjectMeta: metav1.ObjectMeta{Name: "good-project", Namespace: "argocd"}, + } + appSet := v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSetSpec{ + GoTemplate: true, + Generators: []v1alpha1.ApplicationSetGenerator{ + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{{ + Raw: []byte(`{"project": "good-project"}`), + }, { + Raw: []byte(`{"project": "bad-project"}`), + }}, + }, + }, + }, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ + Name: "{{.project}}", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSpec{ + Source: &v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"}, + Project: "{{.project}}", + Destination: v1alpha1.ApplicationDestination{Server: "https://kubernetes.default.svc"}, + }, + }, + }, + } + + kubeclientset := kubefake.NewSimpleClientset() + argoDBMock := dbmocks.ArgoDB{} + argoObjs := []runtime.Object{&project} + + 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, + Renderer: &utils.Render{}, + Recorder: record.NewFakeRecorder(1), + Cache: &fakeCache{}, + Generators: map[string]generators.Generator{ + "List": generators.NewListGenerator(), + }, + ArgoDB: &argoDBMock, + ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), + KubeClientset: kubeclientset, + Policy: v1alpha1.ApplicationsSyncPolicySync, + ArgoCDNamespace: "argocd", + } + + req := ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: "argocd", + Name: "name", + }, + } + + // Verify that on validation error, no error is returned, but the object is requeued + res, err := r.Reconcile(context.Background(), req) + assert.Nil(t, err) + assert.True(t, res.RequeueAfter == ReconcileRequeueOnValidationError) + + var app v1alpha1.Application + + // make sure good app got created + err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-project"}, &app) + assert.NoError(t, err) + assert.Equal(t, app.Name, "good-project") + + // make sure bad app was not created + err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "bad-project"}, &app) + assert.Error(t, err) +} + +func TestReconcilerCreateAppsRecoveringRenderError(t *testing.T) { + + scheme := runtime.NewScheme() + err := v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + err = v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + + project := v1alpha1.AppProject{ + ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "argocd"}, + } + appSet := v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSetSpec{ + GoTemplate: true, + Generators: []v1alpha1.ApplicationSetGenerator{ + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{{ + Raw: []byte(`{"name": "very-good-app"}`), + }, { + Raw: []byte(`{"name": "bad-app"}`), + }}, + }, + }, + }, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ + Name: "{{ index (splitList \"-\" .name ) 2 }}", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSpec{ + Source: &v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"}, + Project: "default", + Destination: v1alpha1.ApplicationDestination{Server: "https://kubernetes.default.svc"}, + }, + }, + }, + } + + kubeclientset := kubefake.NewSimpleClientset() + argoDBMock := dbmocks.ArgoDB{} + argoObjs := []runtime.Object{&project} + + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() + + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Renderer: &utils.Render{}, + Recorder: record.NewFakeRecorder(1), + Cache: &fakeCache{}, + Generators: map[string]generators.Generator{ + "List": generators.NewListGenerator(), + }, + ArgoDB: &argoDBMock, + ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), + KubeClientset: kubeclientset, + Policy: v1alpha1.ApplicationsSyncPolicySync, + ArgoCDNamespace: "argocd", + } + + req := ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: "argocd", + Name: "name", + }, + } + + // Verify that on generatorsError, no error is returned, but the object is requeued + res, err := r.Reconcile(context.Background(), req) + assert.Nil(t, err) + assert.True(t, res.RequeueAfter == ReconcileRequeueOnValidationError) + + var app v1alpha1.Application + + // make sure good app got created + err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "app"}, &app) + assert.NoError(t, err) + assert.Equal(t, app.Name, "app") +} + +func TestSetApplicationSetStatusCondition(t *testing.T) { + scheme := runtime.NewScheme() + err := v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + err = v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + + appSet := v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ + {List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{{ + Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`), + }}, + }}, + }, + Template: v1alpha1.ApplicationSetTemplate{}, + }, + } + + appCondition := v1alpha1.ApplicationSetCondition{ + Type: v1alpha1.ApplicationSetConditionResourcesUpToDate, + Message: "All applications have been generated successfully", + Reason: v1alpha1.ApplicationSetReasonApplicationSetUpToDate, + Status: v1alpha1.ApplicationSetConditionStatusTrue, + } + + kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...) + argoDBMock := dbmocks.ArgoDB{} + argoObjs := []runtime.Object{} + + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() + + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Renderer: &utils.Render{}, + Recorder: record.NewFakeRecorder(1), + Cache: &fakeCache{}, + Generators: map[string]generators.Generator{ + "List": generators.NewListGenerator(), + }, + ArgoDB: &argoDBMock, + ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), + KubeClientset: kubeclientset, + } + + err = r.setApplicationSetStatusCondition(context.TODO(), &appSet, appCondition, true) + assert.Nil(t, err) + + assert.Len(t, appSet.Status.Conditions, 3) +} + +func applicationsUpdateSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alpha1.ApplicationsSyncPolicy, recordBuffer int, allowPolicyOverride bool) v1alpha1.Application { + + scheme := runtime.NewScheme() + err := v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + err = v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + + defaultProject := v1alpha1.AppProject{ + ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "argocd"}, + Spec: v1alpha1.AppProjectSpec{SourceRepos: []string{"*"}, Destinations: []v1alpha1.ApplicationDestination{{Namespace: "*", Server: "https://good-cluster"}}}, + } + appSet := v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{{ + Raw: []byte(`{"cluster": "good-cluster","url": "https://good-cluster"}`), + }}, + }, + }, + }, + SyncPolicy: &v1alpha1.ApplicationSetSyncPolicy{ + ApplicationsSync: &applicationsSyncPolicy, + }, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ + Name: "{{cluster}}", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSpec{ + Source: &v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"}, + Project: "default", + Destination: v1alpha1.ApplicationDestination{Server: "{{url}}"}, + }, + }, + }, + } + + kubeclientset := kubefake.NewSimpleClientset() + argoDBMock := dbmocks.ArgoDB{} + argoObjs := []runtime.Object{&defaultProject} + + 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{ + goodCluster, + }}, nil) + + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Renderer: &utils.Render{}, + Recorder: record.NewFakeRecorder(recordBuffer), + Cache: &fakeCache{}, + Generators: map[string]generators.Generator{ + "List": generators.NewListGenerator(), + }, + ArgoDB: &argoDBMock, + ArgoCDNamespace: "argocd", + ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), + KubeClientset: kubeclientset, + Policy: v1alpha1.ApplicationsSyncPolicySync, + EnablePolicyOverride: allowPolicyOverride, + } + + req := ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: "argocd", + Name: "name", + }, + } + + // Verify that on validation error, no error is returned, but the object is requeued + resCreate, err := r.Reconcile(context.Background(), req) + assert.Nil(t, err) + assert.True(t, resCreate.RequeueAfter == 0) + + var app v1alpha1.Application + + // make sure good app got created + err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app) + assert.Nil(t, err) + assert.Equal(t, app.Name, "good-cluster") + + // Update resource + var retrievedApplicationSet v1alpha1.ApplicationSet + err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &retrievedApplicationSet) + assert.Nil(t, err) + + retrievedApplicationSet.Spec.Template.Annotations = map[string]string{"annotation-key": "annotation-value"} + retrievedApplicationSet.Spec.Template.Labels = map[string]string{"label-key": "label-value"} + + retrievedApplicationSet.Spec.Template.Spec.Source.Helm = &v1alpha1.ApplicationSourceHelm{ + Values: "global.test: test", + } + + err = r.Client.Update(context.TODO(), &retrievedApplicationSet) + assert.Nil(t, err) + + resUpdate, err := r.Reconcile(context.Background(), req) + assert.Nil(t, err) + + err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app) + assert.Nil(t, err) + assert.True(t, resUpdate.RequeueAfter == 0) + assert.Equal(t, app.Name, "good-cluster") + + return app +} + +func TestUpdateNotPerformedWithSyncPolicyCreateOnly(t *testing.T) { + + applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateOnly + + app := applicationsUpdateSyncPolicyTest(t, applicationsSyncPolicy, 1, true) + + assert.Nil(t, app.Spec.Source.Helm) + assert.Nil(t, app.ObjectMeta.Annotations) +} + +func TestUpdateNotPerformedWithSyncPolicyCreateDelete(t *testing.T) { - argoDBMock := dbmocks.ArgoDB{} - argoDBMock.On("GetCluster", mock.Anything, "https://kubernetes.default.svc").Return(&myCluster, nil) - argoDBMock.On("ListClusters", mock.Anything).Return(&argov1alpha1.ClusterList{Items: []argov1alpha1.Cluster{ - myCluster, - }}, nil) + applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateDelete - argoObjs := []runtime.Object{myProject} - for _, app := range cc.apps { - argoObjs = append(argoObjs, &app) - } + app := applicationsUpdateSyncPolicyTest(t, applicationsSyncPolicy, 1, true) - r := ApplicationSetReconciler{ - Client: client, - Scheme: scheme, - Recorder: record.NewFakeRecorder(1), - Generators: map[string]generators.Generator{}, - ArgoDB: &argoDBMock, - ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), - KubeClientset: kubeclientset, - } + assert.Nil(t, app.Spec.Source.Helm) + assert.Nil(t, app.ObjectMeta.Annotations) +} - appSetInfo := argov1alpha1.ApplicationSet{} +func TestUpdatePerformedWithSyncPolicyCreateUpdate(t *testing.T) { - validationErrors, _ := r.validateGeneratedApplications(context.TODO(), cc.apps, appSetInfo, "namespace") - var errorMessages []string - for _, v := range validationErrors { - errorMessages = append(errorMessages, v.Error()) - } + applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateUpdate - if len(errorMessages) == 0 { - assert.Equal(t, len(cc.expectedErrors), 0, "Expected errors but none were seen") - } else { - // An error was returned: it should be expected - matched := false - for _, expectedErr := range cc.expectedErrors { - foundMatch := strings.Contains(strings.Join(errorMessages, ";"), expectedErr) - assert.True(t, foundMatch, "Unble to locate expected error: %s", cc.expectedErrors) - matched = matched || foundMatch - } - assert.True(t, matched, "An unexpected error occurrred: %v", err) - // validation message was returned: it should be expected - matched = false - foundMatch := reflect.DeepEqual(validationErrors, cc.validationErrors) - var message string - for _, v := range validationErrors { - message = v.Error() - break - } - assert.True(t, foundMatch, "Unble to locate validation message: %s", message) - matched = matched || foundMatch - assert.True(t, matched, "An unexpected error occurrred: %v", err) - } - }) - } + app := applicationsUpdateSyncPolicyTest(t, applicationsSyncPolicy, 2, true) + + assert.Equal(t, "global.test: test", app.Spec.Source.Helm.Values) + assert.Equal(t, map[string]string{"annotation-key": "annotation-value"}, app.ObjectMeta.Annotations) + assert.Equal(t, map[string]string{"label-key": "label-value"}, app.ObjectMeta.Labels) +} + +func TestUpdatePerformedWithSyncPolicySync(t *testing.T) { + + applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicySync + + app := applicationsUpdateSyncPolicyTest(t, applicationsSyncPolicy, 2, true) + + assert.Equal(t, "global.test: test", app.Spec.Source.Helm.Values) + assert.Equal(t, map[string]string{"annotation-key": "annotation-value"}, app.ObjectMeta.Annotations) + assert.Equal(t, map[string]string{"label-key": "label-value"}, app.ObjectMeta.Labels) +} + +func TestUpdatePerformedWithSyncPolicyCreateOnlyAndAllowPolicyOverrideFalse(t *testing.T) { + + applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateOnly + + app := applicationsUpdateSyncPolicyTest(t, applicationsSyncPolicy, 2, false) + + assert.Equal(t, "global.test: test", app.Spec.Source.Helm.Values) + assert.Equal(t, map[string]string{"annotation-key": "annotation-value"}, app.ObjectMeta.Annotations) + assert.Equal(t, map[string]string{"label-key": "label-value"}, app.ObjectMeta.Labels) } -func TestReconcilerValidationErrorBehaviour(t *testing.T) { +func applicationsDeleteSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alpha1.ApplicationsSyncPolicy, recordBuffer int, allowPolicyOverride bool) v1alpha1.ApplicationList { scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) + err := v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - err = argov1alpha1.AddToScheme(scheme) + err = v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - defaultProject := argov1alpha1.AppProject{ + defaultProject := v1alpha1.AppProject{ ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "argocd"}, - Spec: argov1alpha1.AppProjectSpec{SourceRepos: []string{"*"}, Destinations: []argov1alpha1.ApplicationDestination{{Namespace: "*", Server: "https://good-cluster"}}}, + Spec: v1alpha1.AppProjectSpec{SourceRepos: []string{"*"}, Destinations: []v1alpha1.ApplicationDestination{{Namespace: "*", Server: "https://good-cluster"}}}, } - appSet := argov1alpha1.ApplicationSet{ + appSet := v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - GoTemplate: true, - Generators: []argov1alpha1.ApplicationSetGenerator{ + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ { - List: &argov1alpha1.ListGenerator{ + List: &v1alpha1.ListGenerator{ Elements: []apiextensionsv1.JSON{{ Raw: []byte(`{"cluster": "good-cluster","url": "https://good-cluster"}`), - }, { - Raw: []byte(`{"cluster": "bad-cluster","url": "https://bad-cluster"}`), }}, }, }, }, - Template: argov1alpha1.ApplicationSetTemplate{ - ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{ - Name: "{{.cluster}}", + SyncPolicy: &v1alpha1.ApplicationSetSyncPolicy{ + ApplicationsSync: &applicationsSyncPolicy, + }, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ + Name: "{{cluster}}", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSpec{ - Source: &argov1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"}, + Spec: v1alpha1.ApplicationSpec{ + Source: &v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"}, Project: "default", - Destination: argov1alpha1.ApplicationDestination{Server: "{{.url}}"}, + Destination: v1alpha1.ApplicationDestination{Server: "{{url}}"}, }, }, }, @@ -1826,12 +2783,10 @@ func TestReconcilerValidationErrorBehaviour(t *testing.T) { argoDBMock := dbmocks.ArgoDB{} argoObjs := []runtime.Object{&defaultProject} - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).Build() - goodCluster := argov1alpha1.Cluster{Server: "https://good-cluster", Name: "good-cluster"} - badCluster := argov1alpha1.Cluster{Server: "https://bad-cluster", Name: "bad-cluster"} + 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("GetCluster", mock.Anything, "https://bad-cluster").Return(&badCluster, nil) - argoDBMock.On("ListClusters", mock.Anything).Return(&argov1alpha1.ClusterList{Items: []argov1alpha1.Cluster{ + argoDBMock.On("ListClusters", mock.Anything).Return(&v1alpha1.ClusterList{Items: []v1alpha1.Cluster{ goodCluster, }}, nil) @@ -1839,14 +2794,17 @@ func TestReconcilerValidationErrorBehaviour(t *testing.T) { Client: client, Scheme: scheme, Renderer: &utils.Render{}, - Recorder: record.NewFakeRecorder(1), + Recorder: record.NewFakeRecorder(recordBuffer), + Cache: &fakeCache{}, Generators: map[string]generators.Generator{ "List": generators.NewListGenerator(), }, - ArgoDB: &argoDBMock, - ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), - KubeClientset: kubeclientset, - Policy: &utils.SyncPolicy{}, + ArgoDB: &argoDBMock, + ArgoCDNamespace: "argocd", + ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), + KubeClientset: kubeclientset, + Policy: v1alpha1.ApplicationsSyncPolicySync, + EnablePolicyOverride: allowPolicyOverride, } req := ctrl.Request{ @@ -1857,76 +2815,87 @@ func TestReconcilerValidationErrorBehaviour(t *testing.T) { } // Verify that on validation error, no error is returned, but the object is requeued - res, err := r.Reconcile(context.Background(), req) + resCreate, err := r.Reconcile(context.Background(), req) assert.Nil(t, err) - assert.True(t, res.RequeueAfter == 0) + assert.True(t, resCreate.RequeueAfter == 0) - var app argov1alpha1.Application + var app v1alpha1.Application // make sure good app got created err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "good-cluster"}, &app) - assert.NoError(t, err) + assert.Nil(t, err) assert.Equal(t, app.Name, "good-cluster") - // make sure bad app was not created - err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "bad-cluster"}, &app) - assert.Error(t, err) -} - -func TestSetApplicationSetStatusCondition(t *testing.T) { - scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) - assert.Nil(t, err) - err = argov1alpha1.AddToScheme(scheme) + // Update resource + var retrievedApplicationSet v1alpha1.ApplicationSet + err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &retrievedApplicationSet) assert.Nil(t, err) - - appSet := argov1alpha1.ApplicationSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "name", - Namespace: "argocd", - }, - Spec: argov1alpha1.ApplicationSetSpec{ - Generators: []argov1alpha1.ApplicationSetGenerator{ - {List: &argov1alpha1.ListGenerator{ - Elements: []apiextensionsv1.JSON{{ - Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`), - }}, - }}, + retrievedApplicationSet.Spec.Generators = []v1alpha1.ApplicationSetGenerator{ + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{}, }, - Template: argov1alpha1.ApplicationSetTemplate{}, }, } - appCondition := argov1alpha1.ApplicationSetCondition{ - Type: argov1alpha1.ApplicationSetConditionResourcesUpToDate, - Message: "All applications have been generated successfully", - Reason: argov1alpha1.ApplicationSetReasonApplicationSetUpToDate, - Status: argov1alpha1.ApplicationSetConditionStatusTrue, - } - - kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...) - argoDBMock := dbmocks.ArgoDB{} - argoObjs := []runtime.Object{} + err = r.Client.Update(context.TODO(), &retrievedApplicationSet) + assert.Nil(t, err) - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).Build() + resUpdate, err := r.Reconcile(context.Background(), req) + assert.Nil(t, err) - r := ApplicationSetReconciler{ - Client: client, - Scheme: scheme, - Renderer: &utils.Render{}, - Recorder: record.NewFakeRecorder(1), - Generators: map[string]generators.Generator{ - "List": generators.NewListGenerator(), - }, - ArgoDB: &argoDBMock, - ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), - KubeClientset: kubeclientset, - } + var apps v1alpha1.ApplicationList - err = r.setApplicationSetStatusCondition(context.TODO(), &appSet, appCondition, true) + err = r.Client.List(context.TODO(), &apps) assert.Nil(t, err) + assert.True(t, resUpdate.RequeueAfter == 0) - assert.Len(t, appSet.Status.Conditions, 3) + return apps +} + +func TestDeleteNotPerformedWithSyncPolicyCreateOnly(t *testing.T) { + + applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateOnly + + apps := applicationsDeleteSyncPolicyTest(t, applicationsSyncPolicy, 1, true) + + assert.Equal(t, "good-cluster", apps.Items[0].Name) +} + +func TestDeleteNotPerformedWithSyncPolicyCreateUpdate(t *testing.T) { + + applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateUpdate + + apps := applicationsDeleteSyncPolicyTest(t, applicationsSyncPolicy, 2, true) + + assert.Equal(t, "good-cluster", apps.Items[0].Name) +} + +func TestDeletePerformedWithSyncPolicyCreateDelete(t *testing.T) { + + applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateDelete + + apps := applicationsDeleteSyncPolicyTest(t, applicationsSyncPolicy, 3, true) + + assert.Equal(t, 0, len(apps.Items)) +} + +func TestDeletePerformedWithSyncPolicySync(t *testing.T) { + + applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicySync + + apps := applicationsDeleteSyncPolicyTest(t, applicationsSyncPolicy, 3, true) + + assert.Equal(t, 0, len(apps.Items)) +} + +func TestDeletePerformedWithSyncPolicyCreateOnlyAndAllowPolicyOverrideFalse(t *testing.T) { + + applicationsSyncPolicy := v1alpha1.ApplicationsSyncPolicyCreateOnly + + apps := applicationsDeleteSyncPolicyTest(t, applicationsSyncPolicy, 3, false) + + assert.Equal(t, 0, len(apps.Items)) } // Test app generation from a go template application set using a pull request generator @@ -1937,42 +2906,52 @@ func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) { for _, cases := range []struct { name string params []map[string]interface{} - template argov1alpha1.ApplicationSetTemplate - expectedApp []argov1alpha1.Application + template v1alpha1.ApplicationSetTemplate + expectedApp []v1alpha1.Application }{ { 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"}}}, - template: argov1alpha1.ApplicationSetTemplate{ - ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{ + "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: argov1alpha1.ApplicationSpec{ - Source: &argov1alpha1.ApplicationSource{ + Spec: v1alpha1.ApplicationSpec{ + Source: &v1alpha1.ApplicationSource{ RepoURL: "https://testurl/testRepo", TargetRevision: "{{.head_short_sha}}", }, - Destination: argov1alpha1.ApplicationDestination{ + Destination: v1alpha1.ApplicationDestination{ Server: "https://kubernetes.default.svc", Namespace: "AppSet-{{.branch_slug}}-{{.head_sha}}", }, }, }, - expectedApp: []argov1alpha1.Application{ + expectedApp: []v1alpha1.Application{ { 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{ @@ -1993,8 +2972,8 @@ func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) { t.Run(cases.name, func(t *testing.T) { generatorMock := generatorMock{} - generator := argov1alpha1.ApplicationSetGenerator{ - PullRequest: &argov1alpha1.PullRequestGenerator{}, + generator := v1alpha1.ApplicationSetGenerator{ + PullRequest: &v1alpha1.PullRequestGenerator{}, } generatorMock.On("GenerateParams", &generator). @@ -2007,6 +2986,7 @@ func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) { Client: client, Scheme: scheme, Recorder: record.NewFakeRecorder(1), + Cache: &fakeCache{}, Generators: map[string]generators.Generator{ "PullRequest": &generatorMock, }, @@ -2014,11 +2994,11 @@ func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) { KubeClientset: kubefake.NewSimpleClientset(), } - gotApp, _, _ := appSetReconciler.generateApplications(argov1alpha1.ApplicationSet{ - Spec: argov1alpha1.ApplicationSetSpec{ + gotApp, _, _ := appSetReconciler.generateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{ + Spec: v1alpha1.ApplicationSetSpec{ GoTemplate: true, - Generators: []argov1alpha1.ApplicationSetGenerator{{ - PullRequest: &argov1alpha1.PullRequestGenerator{}, + Generators: []v1alpha1.ApplicationSetGenerator{{ + PullRequest: &v1alpha1.PullRequestGenerator{}, }}, Template: cases.template, }, @@ -2034,17 +3014,17 @@ func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) { func TestPolicies(t *testing.T) { scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) + err := v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - err = argov1alpha1.AddToScheme(scheme) + err = v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - defaultProject := argov1alpha1.AppProject{ + defaultProject := v1alpha1.AppProject{ ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "argocd"}, - Spec: argov1alpha1.AppProjectSpec{SourceRepos: []string{"*"}, Destinations: []argov1alpha1.ApplicationDestination{{Namespace: "*", Server: "https://kubernetes.default.svc"}}}, + Spec: v1alpha1.AppProjectSpec{SourceRepos: []string{"*"}, Destinations: []v1alpha1.ApplicationDestination{{Namespace: "*", Server: "https://kubernetes.default.svc"}}}, } - myCluster := argov1alpha1.Cluster{ + myCluster := v1alpha1.Cluster{ Server: "https://kubernetes.default.svc", Name: "my-cluster", } @@ -2089,16 +3069,16 @@ func TestPolicies(t *testing.T) { policy := utils.Policies[c.policyName] assert.NotNil(t, policy) - appSet := argov1alpha1.ApplicationSet{ + appSet := v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ + Spec: v1alpha1.ApplicationSetSpec{ GoTemplate: true, - Generators: []argov1alpha1.ApplicationSetGenerator{ + Generators: []v1alpha1.ApplicationSetGenerator{ { - List: &argov1alpha1.ListGenerator{ + List: &v1alpha1.ListGenerator{ Elements: []apiextensionsv1.JSON{ { Raw: []byte(`{"name": "my-app"}`), @@ -2107,34 +3087,36 @@ func TestPolicies(t *testing.T) { }, }, }, - Template: argov1alpha1.ApplicationSetTemplate{ - ApplicationSetTemplateMeta: argov1alpha1.ApplicationSetTemplateMeta{ + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ Name: "{{.name}}", Namespace: "argocd", Annotations: map[string]string{ "key": "value", }, }, - Spec: argov1alpha1.ApplicationSpec{ - Source: &argov1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"}, + Spec: v1alpha1.ApplicationSpec{ + Source: &v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"}, Project: "default", - Destination: argov1alpha1.ApplicationDestination{Server: "https://kubernetes.default.svc"}, + Destination: v1alpha1.ApplicationDestination{Server: "https://kubernetes.default.svc"}, }, }, }, } - 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, Scheme: scheme, Renderer: &utils.Render{}, Recorder: record.NewFakeRecorder(10), + Cache: &fakeCache{}, Generators: map[string]generators.Generator{ "List": generators.NewListGenerator(), }, ArgoDB: &argoDBMock, + ArgoCDNamespace: "argocd", ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), KubeClientset: kubeclientset, Policy: policy, @@ -2152,7 +3134,7 @@ func TestPolicies(t *testing.T) { assert.Nil(t, err) assert.True(t, res.RequeueAfter == 0) - var app argov1alpha1.Application + var app v1alpha1.Application err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "my-app"}, &app) assert.NoError(t, err) assert.Equal(t, app.Annotations["key"], "value") @@ -2178,8 +3160,8 @@ func TestPolicies(t *testing.T) { // Check if Application is deleted err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "name"}, &appSet) assert.NoError(t, err) - appSet.Spec.Generators[0] = argov1alpha1.ApplicationSetGenerator{ - List: &argov1alpha1.ListGenerator{ + appSet.Spec.Generators[0] = v1alpha1.ApplicationSetGenerator{ + List: &v1alpha1.ListGenerator{ Elements: []apiextensionsv1.JSON{}, }, } @@ -2203,124 +3185,174 @@ func TestPolicies(t *testing.T) { func TestSetApplicationSetApplicationStatus(t *testing.T) { scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) + err := v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - err = argov1alpha1.AddToScheme(scheme) + err = v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - appSet := argov1alpha1.ApplicationSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "name", - Namespace: "argocd", - }, - Spec: argov1alpha1.ApplicationSetSpec{ - Generators: []argov1alpha1.ApplicationSetGenerator{ - {List: &argov1alpha1.ListGenerator{ - Elements: []apiextensionsv1.JSON{{ - Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`), - }}, - }}, + kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...) + argoDBMock := dbmocks.ArgoDB{} + argoObjs := []runtime.Object{} + + for _, cc := range []struct { + name string + appSet v1alpha1.ApplicationSet + appStatuses []v1alpha1.ApplicationSetApplicationStatus + expectedAppStatuses []v1alpha1.ApplicationSetApplicationStatus + }{ + { + name: "sets a single appstatus", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ + {List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{{ + Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`), + }}, + }}, + }, + Template: v1alpha1.ApplicationSetTemplate{}, + }, + }, + appStatuses: []v1alpha1.ApplicationSetApplicationStatus{ + { + Application: "app1", + Message: "testing SetApplicationSetApplicationStatus to Healthy", + Status: "Healthy", + }, + }, + expectedAppStatuses: []v1alpha1.ApplicationSetApplicationStatus{ + { + Application: "app1", + Message: "testing SetApplicationSetApplicationStatus to Healthy", + Status: "Healthy", + }, }, - Template: argov1alpha1.ApplicationSetTemplate{}, }, - } - - appStatuses := []argov1alpha1.ApplicationSetApplicationStatus{ { - Application: "my-application", - LastTransitionTime: &metav1.Time{}, - Message: "testing SetApplicationSetApplicationStatus to Healthy", - Status: "Healthy", + name: "removes an appstatus", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ + {List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{{ + Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`), + }}, + }}, + }, + Template: v1alpha1.ApplicationSetTemplate{}, + }, + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ + { + Application: "app1", + Message: "testing SetApplicationSetApplicationStatus to Healthy", + Status: "Healthy", + }, + }, + }, + }, + appStatuses: []v1alpha1.ApplicationSetApplicationStatus{}, + expectedAppStatuses: nil, }, - } + } { - kubeclientset := kubefake.NewSimpleClientset([]runtime.Object{}...) - argoDBMock := dbmocks.ArgoDB{} - argoObjs := []runtime.Object{} + t.Run(cc.name, func(t *testing.T) { - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).Build() + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&cc.appSet).Build() - r := ApplicationSetReconciler{ - Client: client, - Scheme: scheme, - Renderer: &utils.Render{}, - Recorder: record.NewFakeRecorder(1), - Generators: map[string]generators.Generator{ - "List": generators.NewListGenerator(), - }, - ArgoDB: &argoDBMock, - ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), - KubeClientset: kubeclientset, - } + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Renderer: &utils.Render{}, + Recorder: record.NewFakeRecorder(1), + Cache: &fakeCache{}, + Generators: map[string]generators.Generator{ + "List": generators.NewListGenerator(), + }, + ArgoDB: &argoDBMock, + ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), + KubeClientset: kubeclientset, + } - err = r.setAppSetApplicationStatus(context.TODO(), &appSet, appStatuses) - assert.Nil(t, err) + err = r.setAppSetApplicationStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.appStatuses) + assert.Nil(t, err) - assert.Len(t, appSet.Status.ApplicationStatus, 1) + assert.Equal(t, cc.expectedAppStatuses, cc.appSet.Status.ApplicationStatus) + }) + } } func TestBuildAppDependencyList(t *testing.T) { scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) + err := v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - err = argov1alpha1.AddToScheme(scheme) + err = v1alpha1.AddToScheme(scheme) assert.Nil(t, err) client := fake.NewClientBuilder().WithScheme(scheme).Build() for _, cc := range []struct { name string - appSet argov1alpha1.ApplicationSet - apps []argov1alpha1.Application + appSet v1alpha1.ApplicationSet + apps []v1alpha1.Application expectedList [][]string expectedStepMap map[string]int }{ { name: "handles an empty set of applications and no strategy", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{}, + Spec: v1alpha1.ApplicationSetSpec{}, }, - apps: []argov1alpha1.Application{}, + apps: []v1alpha1.Application{}, expectedList: [][]string{}, expectedStepMap: map[string]int{}, }, { name: "handles an empty set of applications and ignores AllAtOnce strategy", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "AllAtOnce", }, }, }, - apps: []argov1alpha1.Application{}, + apps: []v1alpha1.Application{}, expectedList: [][]string{}, expectedStepMap: map[string]int{}, }, { name: "handles an empty set of applications with good 'In' selectors", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ { Key: "env", Operator: "In", @@ -2335,7 +3367,7 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, }, - apps: []argov1alpha1.Application{}, + apps: []v1alpha1.Application{}, expectedList: [][]string{ {}, }, @@ -2343,18 +3375,18 @@ func TestBuildAppDependencyList(t *testing.T) { }, { name: "handles selecting 1 application with 1 'In' selector", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ { Key: "env", Operator: "In", @@ -2369,7 +3401,7 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app-dev", @@ -2388,18 +3420,18 @@ func TestBuildAppDependencyList(t *testing.T) { }, { name: "handles 'In' selectors that select no applications", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ { Key: "env", Operator: "In", @@ -2410,7 +3442,7 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ { Key: "env", Operator: "In", @@ -2421,7 +3453,7 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ { Key: "env", Operator: "In", @@ -2436,7 +3468,7 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app-qa", @@ -2466,18 +3498,18 @@ func TestBuildAppDependencyList(t *testing.T) { }, { name: "multiple 'In' selectors in the same matchExpression only select Applications that match all selectors", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ { Key: "region", Operator: "In", @@ -2499,7 +3531,7 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app-qa1", @@ -2527,18 +3559,18 @@ func TestBuildAppDependencyList(t *testing.T) { }, { name: "multiple values in the same 'In' matchExpression can match on any value", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ { Key: "env", Operator: "In", @@ -2554,7 +3586,7 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app-dev", @@ -2591,18 +3623,18 @@ func TestBuildAppDependencyList(t *testing.T) { }, { name: "handles an empty set of applications with good 'NotIn' selectors", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ { Key: "env", Operator: "In", @@ -2617,31 +3649,76 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, }, - apps: []argov1alpha1.Application{}, + apps: []v1alpha1.Application{}, expectedList: [][]string{ {}, }, - expectedStepMap: map[string]int{}, + expectedStepMap: map[string]int{}, + }, + { + name: "selects 1 application with 1 'NotIn' selector", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ + Type: "RollingSync", + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ + { + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ + { + Key: "env", + Operator: "NotIn", + Values: []string{ + "qa", + }, + }, + }, + }, + }, + }, + }, + }, + }, + apps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app-dev", + Labels: map[string]string{ + "env": "dev", + }, + }, + }, + }, + expectedList: [][]string{ + {"app-dev"}, + }, + expectedStepMap: map[string]int{ + "app-dev": 0, + }, }, { - name: "selects 1 application with 1 'NotIn' selector", - appSet: argov1alpha1.ApplicationSet{ + name: "'NotIn' selectors that select no applications", + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ { Key: "env", Operator: "NotIn", Values: []string{ - "qa", + "dev", }, }, }, @@ -2651,42 +3728,58 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ - Name: "app-dev", + Name: "app-qa", Labels: map[string]string{ - "env": "dev", + "env": "qa", + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app-prod", + Labels: map[string]string{ + "env": "prod", }, }, }, }, expectedList: [][]string{ - {"app-dev"}, + {"app-qa", "app-prod"}, }, expectedStepMap: map[string]int{ - "app-dev": 0, + "app-qa": 0, + "app-prod": 0, }, }, { - name: "'NotIn' selectors that select no applications", - appSet: argov1alpha1.ApplicationSet{ + name: "multiple 'NotIn' selectors remove Applications with mising labels on any match", + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ + { + Key: "region", + Operator: "NotIn", + Values: []string{ + "us-east-2", + }, + }, { Key: "env", Operator: "NotIn", Values: []string{ - "dev", + "qa", }, }, }, @@ -2696,10 +3789,10 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ - Name: "app-qa", + Name: "app-qa1", Labels: map[string]string{ "env": "qa", }, @@ -2707,35 +3800,33 @@ func TestBuildAppDependencyList(t *testing.T) { }, { ObjectMeta: metav1.ObjectMeta{ - Name: "app-prod", + Name: "app-qa2", Labels: map[string]string{ - "env": "prod", + "env": "qa", + "region": "us-east-2", }, }, }, }, expectedList: [][]string{ - {"app-qa", "app-prod"}, - }, - expectedStepMap: map[string]int{ - "app-qa": 0, - "app-prod": 0, + {}, }, + expectedStepMap: map[string]int{}, }, { - name: "multiple 'NotIn' selectors only match Applications with all labels", - appSet: argov1alpha1.ApplicationSet{ + name: "multiple 'NotIn' selectors filter all matching Applications", + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ { Key: "region", Operator: "NotIn", @@ -2757,12 +3848,13 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app-qa1", Labels: map[string]string{ - "env": "qa", + "env": "qa", + "region": "us-east-1", }, }, }, @@ -2775,28 +3867,46 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app-prod1", + Labels: map[string]string{ + "env": "prod", + "region": "us-east-1", + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app-prod2", + Labels: map[string]string{ + "env": "prod", + "region": "us-east-2", + }, + }, + }, }, expectedList: [][]string{ - {"app-qa1"}, + {"app-prod1"}, }, expectedStepMap: map[string]int{ - "app-qa1": 0, + "app-prod1": 0, }, }, { name: "multiple values in the same 'NotIn' matchExpression exclude a match from any value", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ { Key: "env", Operator: "NotIn", @@ -2812,7 +3922,7 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app-dev", @@ -2848,18 +3958,18 @@ func TestBuildAppDependencyList(t *testing.T) { }, { name: "in a mix of 'In' and 'NotIn' selectors, 'NotIn' takes precedence", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{ + MatchExpressions: []v1alpha1.ApplicationMatchExpression{ { Key: "env", Operator: "In", @@ -2882,7 +3992,7 @@ func TestBuildAppDependencyList(t *testing.T) { }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app-dev", @@ -2929,13 +4039,14 @@ func TestBuildAppDependencyList(t *testing.T) { Client: client, Scheme: scheme, Recorder: record.NewFakeRecorder(1), + Cache: &fakeCache{}, Generators: map[string]generators.Generator{}, ArgoDB: &argoDBMock, ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), 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") @@ -2946,32 +4057,32 @@ func TestBuildAppDependencyList(t *testing.T) { func TestBuildAppSyncMap(t *testing.T) { scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) + err := v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - err = argov1alpha1.AddToScheme(scheme) + err = v1alpha1.AddToScheme(scheme) assert.Nil(t, err) client := fake.NewClientBuilder().WithScheme(scheme).Build() for _, cc := range []struct { name string - appSet argov1alpha1.ApplicationSet - appMap map[string]argov1alpha1.Application + appSet v1alpha1.ApplicationSet + appMap map[string]v1alpha1.Application appDependencyList [][]string expectedMap map[string]bool }{ { name: "handles an empty app dependency list", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, }, @@ -2980,15 +4091,15 @@ func TestBuildAppSyncMap(t *testing.T) { }, { name: "handles two applications with no statuses", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, }, @@ -3003,15 +4114,15 @@ func TestBuildAppSyncMap(t *testing.T) { }, { name: "handles applications after an empty selection", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, }, @@ -3026,19 +4137,19 @@ func TestBuildAppSyncMap(t *testing.T) { }, { name: "handles RollingSync applications that are healthy and have no changes", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Status: "Healthy", @@ -3050,20 +4161,20 @@ func TestBuildAppSyncMap(t *testing.T) { }, }, }, - appMap: map[string]argov1alpha1.Application{ + appMap: map[string]v1alpha1.Application{ "app1": { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3071,15 +4182,15 @@ func TestBuildAppSyncMap(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app2", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3095,19 +4206,19 @@ func TestBuildAppSyncMap(t *testing.T) { }, { name: "blocks RollingSync applications that are healthy and have no changes, but are still pending", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Status: "Pending", @@ -3119,20 +4230,20 @@ func TestBuildAppSyncMap(t *testing.T) { }, }, }, - appMap: map[string]argov1alpha1.Application{ + appMap: map[string]v1alpha1.Application{ "app1": { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3140,15 +4251,15 @@ func TestBuildAppSyncMap(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app2", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3164,19 +4275,19 @@ func TestBuildAppSyncMap(t *testing.T) { }, { name: "handles RollingSync applications that are up to date and healthy, but still syncing", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Status: "Progressing", @@ -3188,20 +4299,20 @@ func TestBuildAppSyncMap(t *testing.T) { }, }, }, - appMap: map[string]argov1alpha1.Application{ + appMap: map[string]v1alpha1.Application{ "app1": { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationRunning, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3209,15 +4320,15 @@ func TestBuildAppSyncMap(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app2", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationRunning, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3233,19 +4344,19 @@ func TestBuildAppSyncMap(t *testing.T) { }, { name: "handles RollingSync applications that are up to date and synced, but degraded", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Status: "Progressing", @@ -3257,20 +4368,20 @@ func TestBuildAppSyncMap(t *testing.T) { }, }, }, - appMap: map[string]argov1alpha1.Application{ + appMap: map[string]v1alpha1.Application{ "app1": { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusDegraded, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationRunning, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3278,15 +4389,15 @@ func TestBuildAppSyncMap(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app2", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusDegraded, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationRunning, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3302,19 +4413,19 @@ func TestBuildAppSyncMap(t *testing.T) { }, { name: "handles RollingSync applications that are OutOfSync and healthy", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Status: "Healthy", @@ -3330,20 +4441,20 @@ func TestBuildAppSyncMap(t *testing.T) { {"app1"}, {"app2"}, }, - appMap: map[string]argov1alpha1.Application{ + appMap: map[string]v1alpha1.Application{ "app1": { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeOutOfSync, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, }, }, }, @@ -3351,15 +4462,15 @@ func TestBuildAppSyncMap(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app2", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeOutOfSync, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, }, }, }, @@ -3371,19 +4482,19 @@ func TestBuildAppSyncMap(t *testing.T) { }, { name: "handles a lot of applications", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Status: "Healthy", @@ -3411,20 +4522,20 @@ func TestBuildAppSyncMap(t *testing.T) { }, }, }, - appMap: map[string]argov1alpha1.Application{ + appMap: map[string]v1alpha1.Application{ "app1": { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3432,15 +4543,15 @@ func TestBuildAppSyncMap(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app2", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3448,15 +4559,15 @@ func TestBuildAppSyncMap(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app3", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3464,15 +4575,15 @@ func TestBuildAppSyncMap(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app5", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3480,15 +4591,15 @@ func TestBuildAppSyncMap(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app6", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusDegraded, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, @@ -3522,6 +4633,7 @@ func TestBuildAppSyncMap(t *testing.T) { Client: client, Scheme: scheme, Recorder: record.NewFakeRecorder(1), + Cache: &fakeCache{}, Generators: map[string]generators.Generator{}, ArgoDB: &argoDBMock, ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), @@ -3538,346 +4650,632 @@ func TestBuildAppSyncMap(t *testing.T) { func TestUpdateApplicationSetApplicationStatus(t *testing.T) { scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) + err := v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - err = argov1alpha1.AddToScheme(scheme) + err = v1alpha1.AddToScheme(scheme) assert.Nil(t, err) for _, cc := range []struct { name string - appSet argov1alpha1.ApplicationSet - apps []argov1alpha1.Application - expectedAppStatus []argov1alpha1.ApplicationSetApplicationStatus + appSet v1alpha1.ApplicationSet + apps []v1alpha1.Application + appStepMap map[string]int + expectedAppStatus []v1alpha1.ApplicationSetApplicationStatus }{ { name: "handles a nil list of statuses and no applications", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, }, - apps: []argov1alpha1.Application{}, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{}, + apps: []v1alpha1.Application{}, + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{}, }, { name: "handles a nil list of statuses with a healthy application", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", - Message: "No Application status found, defaulting status to Waiting.", - Status: "Waiting", + Message: "Application resource is already Healthy, updating status from Waiting to Healthy.", + Status: "Healthy", + Step: "1", }, }, }, { name: "handles an empty list of statuses with a healthy application", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, - Status: argov1alpha1.ApplicationSetStatus{}, + Status: v1alpha1.ApplicationSetStatus{}, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", - Message: "No Application status found, defaulting status to Waiting.", - Status: "Waiting", + Message: "Application resource is already Healthy, updating status from Waiting to Healthy.", + Status: "Healthy", + Step: "1", }, }, }, { name: "progresses an OutOfSync RollingSync application to waiting", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "", Status: "Healthy", + Step: "1", }, }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeOutOfSync, + Status: v1alpha1.ApplicationStatus{ + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, }, }, }, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application has pending changes, setting status to Waiting.", Status: "Waiting", + Step: "1", }, }, }, { name: "progresses a pending progressing application to progressing", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "", Status: "Pending", + Step: "1", }, }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusProgressing, }, }, }, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application resource became Progressing, updating status from Pending to Progressing.", Status: "Progressing", + Step: "1", }, }, }, { name: "progresses a pending syncing application to progressing", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "", Status: "Pending", + Step: "1", }, }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationRunning, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application resource became Progressing, updating status from Pending to Progressing.", Status: "Progressing", + Step: "1", }, }, }, { name: "progresses a progressing application to healthy", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "", Status: "Progressing", + Step: "1", }, }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application resource became Healthy, updating status from Progressing to Healthy.", Status: "Healthy", + Step: "1", }, }, }, { name: "progresses a waiting healthy application to healthy", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{}, + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "", Status: "Waiting", + Step: "1", + }, + }, + }, + }, + apps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + }, + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ + Status: health.HealthStatusHealthy, + }, + OperationState: &v1alpha1.OperationState{ + Phase: common.OperationSucceeded, + }, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, + }, + }, + }, + }, + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ + { + Application: "app1", + Message: "Application resource is already Healthy, updating status from Waiting to Healthy.", + Status: "Healthy", + Step: "1", + }, + }, + }, + { + name: "progresses a new outofsync application in a later step to waiting", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ + Type: "RollingSync", + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, + }, + }, + }, + apps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + }, + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ + Status: health.HealthStatusHealthy, + }, + OperationState: &v1alpha1.OperationState{ + Phase: common.OperationSucceeded, + }, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, + }, + }, + }, + }, + appStepMap: map[string]int{ + "app1": 1, + "app2": 0, + }, + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ + { + Application: "app1", + Message: "No Application status found, defaulting status to Waiting.", + Status: "Waiting", + Step: "2", + }, + }, + }, + { + name: "progresses a pending application with a successful sync to progressing", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ + Type: "RollingSync", + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, + }, + }, + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ + { + Application: "app1", + LastTransitionTime: &metav1.Time{ + Time: time.Now().Add(time.Duration(-1) * time.Minute), + }, + Message: "", + Status: "Pending", + Step: "1", + }, + }, + }, + }, + apps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + }, + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ + Status: health.HealthStatusDegraded, + }, + OperationState: &v1alpha1.OperationState{ + Phase: common.OperationSucceeded, + StartedAt: metav1.Time{ + Time: time.Now(), + }, + }, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, + }, + }, + }, + }, + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ + { + Application: "app1", + Message: "Application resource completed a sync successfully, updating status from Pending to Progressing.", + Status: "Progressing", + Step: "1", + }, + }, + }, + { + name: "progresses a pending application with a successful sync <1s ago to progressing", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ + Type: "RollingSync", + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, + }, + }, + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ + { + Application: "app1", + LastTransitionTime: &metav1.Time{ + Time: time.Now(), + }, + Message: "", + Status: "Pending", + Step: "1", + }, + }, + }, + }, + apps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + }, + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ + Status: health.HealthStatusDegraded, + }, + OperationState: &v1alpha1.OperationState{ + Phase: common.OperationSucceeded, + StartedAt: metav1.Time{ + Time: time.Now().Add(time.Duration(-1) * time.Second), + }, + }, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, + }, + }, + }, + }, + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ + { + Application: "app1", + Message: "Application resource completed a sync successfully, updating status from Pending to Progressing.", + Status: "Progressing", + Step: "1", + }, + }, + }, + { + name: "does not progresses a pending application with an old successful sync to progressing", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ + Type: "RollingSync", + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, + }, + }, + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ + { + Application: "app1", + LastTransitionTime: &metav1.Time{ + Time: time.Now(), + }, + Message: "Application moved to Pending status, watching for the Application resource to start Progressing.", + Status: "Pending", + Step: "1", + }, + }, + }, + }, + apps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + }, + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ + Status: health.HealthStatusDegraded, + }, + OperationState: &v1alpha1.OperationState{ + Phase: common.OperationSucceeded, + StartedAt: metav1.Time{ + Time: time.Now().Add(time.Duration(-11) * time.Second), + }, + }, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, + }, + }, + }, + }, + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ + { + Application: "app1", + Message: "Application moved to Pending status, watching for the Application resource to start Progressing.", + Status: "Pending", + Step: "1", + }, + }, + }, + { + name: "removes the appStatus for applications that no longer exist", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ + Type: "RollingSync", + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{}, + }, + }, + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ + { + Application: "app1", + Message: "Application has pending changes, setting status to Waiting.", + Status: "Waiting", + Step: "1", + }, + { + Application: "app2", + Message: "Application has pending changes, setting status to Waiting.", + Status: "Waiting", + Step: "1", }, }, }, }, - apps: []argov1alpha1.Application{ + apps: []v1alpha1.Application{ { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Health: argov1alpha1.HealthStatus{ + Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ Status: health.HealthStatusHealthy, }, - OperationState: &argov1alpha1.OperationState{ + OperationState: &v1alpha1.OperationState{ Phase: common.OperationSucceeded, }, - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeSynced, + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, }, }, }, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application resource is already Healthy, updating status from Waiting to Healthy.", Status: "Healthy", + Step: "1", }, }, }, @@ -3895,13 +5293,14 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) { Client: client, Scheme: scheme, Recorder: record.NewFakeRecorder(1), + Cache: &fakeCache{}, Generators: map[string]generators.Generator{}, ArgoDB: &argoDBMock, ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), KubeClientset: kubeclientset, } - appStatuses, err := r.updateApplicationSetApplicationStatus(context.TODO(), &cc.appSet, cc.apps) + 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 { @@ -3917,93 +5316,93 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) { func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { scheme := runtime.NewScheme() - err := argov1alpha1.AddToScheme(scheme) + err := v1alpha1.AddToScheme(scheme) assert.Nil(t, err) - err = argov1alpha1.AddToScheme(scheme) + err = v1alpha1.AddToScheme(scheme) assert.Nil(t, err) for _, cc := range []struct { name string - appSet argov1alpha1.ApplicationSet + appSet v1alpha1.ApplicationSet appSyncMap map[string]bool appStepMap map[string]int - appMap map[string]argov1alpha1.Application - expectedAppStatus []argov1alpha1.ApplicationSetApplicationStatus + appMap map[string]v1alpha1.Application + expectedAppStatus []v1alpha1.ApplicationSetApplicationStatus }{ { name: "handles an empty appSync and appStepMap", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, }, }, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{}, + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{}, }, }, appSyncMap: map[string]bool{}, appStepMap: map[string]int{}, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{}, + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{}, }, { name: "handles an empty strategy", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{}, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{}, + Spec: v1alpha1.ApplicationSetSpec{}, + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{}, }, }, appSyncMap: map[string]bool{}, appStepMap: map[string]int{}, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{}, + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{}, }, { name: "handles an empty applicationset strategy", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{}, + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{}, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{}, + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{}, }, }, appSyncMap: map[string]bool{}, appStepMap: map[string]int{}, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{}, + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{}, }, { name: "handles an appSyncMap with no existing statuses", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{}, + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{}, }, }, appSyncMap: map[string]bool{ @@ -4014,32 +5413,32 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { "app1": 0, "app2": 1, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{}, + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{}, }, { name: "handles updating a RollingSync status from Waiting to Pending", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, }, }, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", @@ -4054,43 +5453,45 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { appStepMap: map[string]int{ "app1": 0, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", LastTransitionTime: nil, Message: "Application moved to Pending status, watching for the Application resource to start Progressing.", Status: "Pending", + Step: "1", }, }, }, { name: "does not update a RollingSync status if appSyncMap is false", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, }, }, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, }, }, @@ -4101,43 +5502,45 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { appStepMap: map[string]int{ "app1": 0, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", LastTransitionTime: nil, Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, }, }, { name: "does not update a status if status is not pending", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, }, }, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application Pending status timed out while waiting to become Progressing, reset status to Healthy.", Status: "Healthy", + Step: "1", }, }, }, @@ -4148,62 +5551,67 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { appStepMap: map[string]int{ "app1": 0, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", LastTransitionTime: nil, Message: "Application Pending status timed out while waiting to become Progressing, reset status to Healthy.", Status: "Healthy", + Step: "1", }, }, }, { name: "does not update a status if maxUpdate has already been reached with RollingSync", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, MaxUpdate: &intstr.IntOrString{ Type: intstr.Int, IntVal: 3, }, }, { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, }, }, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application resource became Progressing, updating status from Pending to Progressing.", Status: "Progressing", + Step: "1", }, { Application: "app2", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app3", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app4", Message: "Application moved to Pending status, watching for the Application resource to start Progressing.", Status: "Pending", + Step: "1", }, }, }, @@ -4220,14 +5628,14 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { "app3": 0, "app4": 0, }, - appMap: map[string]argov1alpha1.Application{ + appMap: map[string]v1alpha1.Application{ "app1": { ObjectMeta: metav1.ObjectMeta{ Name: "app1", }, - Status: argov1alpha1.ApplicationStatus{ - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeOutOfSync, + Status: v1alpha1.ApplicationStatus{ + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, }, }, }, @@ -4235,9 +5643,9 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app2", }, - Status: argov1alpha1.ApplicationStatus{ - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeOutOfSync, + Status: v1alpha1.ApplicationStatus{ + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, }, }, }, @@ -4245,9 +5653,9 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app3", }, - Status: argov1alpha1.ApplicationStatus{ - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeOutOfSync, + Status: v1alpha1.ApplicationStatus{ + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, }, }, }, @@ -4255,82 +5663,89 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "app4", }, - Status: argov1alpha1.ApplicationStatus{ - Sync: argov1alpha1.SyncStatus{ - Status: argov1alpha1.SyncStatusCodeOutOfSync, + Status: v1alpha1.ApplicationStatus{ + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, }, }, }, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", LastTransitionTime: nil, Message: "Application resource became Progressing, updating status from Pending to Progressing.", Status: "Progressing", + Step: "1", }, { Application: "app2", LastTransitionTime: nil, Message: "Application moved to Pending status, watching for the Application resource to start Progressing.", Status: "Pending", + Step: "1", }, { Application: "app3", LastTransitionTime: nil, Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app4", LastTransitionTime: nil, Message: "Application moved to Pending status, watching for the Application resource to start Progressing.", Status: "Pending", + Step: "1", }, }, }, { name: "rounds down for maxUpdate set to percentage string", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, MaxUpdate: &intstr.IntOrString{ Type: intstr.String, StrVal: "50%", }, }, { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, }, }, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app2", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app3", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, }, }, @@ -4345,69 +5760,75 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { "app2": 0, "app3": 0, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", LastTransitionTime: nil, Message: "Application moved to Pending status, watching for the Application resource to start Progressing.", Status: "Pending", + Step: "1", }, { Application: "app2", LastTransitionTime: nil, Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app3", LastTransitionTime: nil, Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, }, }, { name: "does not update any applications with maxUpdate set to 0", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, MaxUpdate: &intstr.IntOrString{ Type: intstr.Int, IntVal: 0, }, }, { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, }, }, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app2", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app3", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, }, }, @@ -4422,69 +5843,75 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { "app2": 0, "app3": 0, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", LastTransitionTime: nil, Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app2", LastTransitionTime: nil, Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app3", LastTransitionTime: nil, Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, }, }, { name: "updates all applications with maxUpdate set to 100%", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, MaxUpdate: &intstr.IntOrString{ Type: intstr.String, StrVal: "100%", }, }, { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, }, }, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app2", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app3", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, }, }, @@ -4499,69 +5926,75 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { "app2": 0, "app3": 0, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", LastTransitionTime: nil, Message: "Application moved to Pending status, watching for the Application resource to start Progressing.", Status: "Pending", + Step: "1", }, { Application: "app2", LastTransitionTime: nil, Message: "Application moved to Pending status, watching for the Application resource to start Progressing.", Status: "Pending", + Step: "1", }, { Application: "app3", LastTransitionTime: nil, Message: "Application moved to Pending status, watching for the Application resource to start Progressing.", Status: "Pending", + Step: "1", }, }, }, { name: "updates at least 1 application with maxUpdate >0%", - appSet: argov1alpha1.ApplicationSet{ + appSet: v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "argocd", }, - Spec: argov1alpha1.ApplicationSetSpec{ - Strategy: &argov1alpha1.ApplicationSetStrategy{ + Spec: v1alpha1.ApplicationSetSpec{ + Strategy: &v1alpha1.ApplicationSetStrategy{ Type: "RollingSync", - RollingSync: &argov1alpha1.ApplicationSetRolloutStrategy{ - Steps: []argov1alpha1.ApplicationSetRolloutStep{ + RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{ + Steps: []v1alpha1.ApplicationSetRolloutStep{ { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, MaxUpdate: &intstr.IntOrString{ Type: intstr.String, StrVal: "1%", }, }, { - MatchExpressions: []argov1alpha1.ApplicationMatchExpression{}, + MatchExpressions: []v1alpha1.ApplicationMatchExpression{}, }, }, }, }, }, - Status: argov1alpha1.ApplicationSetStatus{ - ApplicationStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + Status: v1alpha1.ApplicationSetStatus{ + ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app2", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app3", Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, }, }, @@ -4576,24 +6009,27 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { "app2": 0, "app3": 0, }, - expectedAppStatus: []argov1alpha1.ApplicationSetApplicationStatus{ + expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{ { Application: "app1", LastTransitionTime: nil, Message: "Application moved to Pending status, watching for the Application resource to start Progressing.", Status: "Pending", + Step: "1", }, { Application: "app2", LastTransitionTime: nil, Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, { Application: "app3", LastTransitionTime: nil, Message: "Application is out of date with the current AppSet generation, setting status to Waiting.", Status: "Waiting", + Step: "1", }, }, }, @@ -4611,13 +6047,14 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { Client: client, Scheme: scheme, Recorder: record.NewFakeRecorder(1), + Cache: &fakeCache{}, Generators: map[string]generators.Generator{}, ArgoDB: &argoDBMock, ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...), 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 { @@ -4629,3 +6066,133 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { }) } } + +func TestOwnsHandler(t *testing.T) { + // progressive syncs do not affect create, delete, or generic + ownsHandler := getOwnsHandlerPredicates(true) + assert.False(t, ownsHandler.CreateFunc(event.CreateEvent{})) + assert.True(t, ownsHandler.DeleteFunc(event.DeleteEvent{})) + assert.True(t, ownsHandler.GenericFunc(event.GenericEvent{})) + ownsHandler = getOwnsHandlerPredicates(false) + assert.False(t, ownsHandler.CreateFunc(event.CreateEvent{})) + assert.True(t, ownsHandler.DeleteFunc(event.DeleteEvent{})) + assert.True(t, ownsHandler.GenericFunc(event.GenericEvent{})) + + now := metav1.Now() + type args struct { + e event.UpdateEvent + enableProgressiveSyncs bool + } + tests := []struct { + name string + args args + want bool + }{ + {name: "SameApplicationReconciledAtDiff", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.Application{Status: v1alpha1.ApplicationStatus{ReconciledAt: &now}}, + ObjectNew: &v1alpha1.Application{Status: v1alpha1.ApplicationStatus{ReconciledAt: &now}}, + }}, want: false}, + {name: "SameApplicationResourceVersionDiff", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "foo", + }}, + ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{ + ResourceVersion: "bar", + }}, + }}, want: false}, + {name: "ApplicationHealthStatusDiff", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.Application{Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ + Status: "Unknown", + }, + }}, + ObjectNew: &v1alpha1.Application{Status: v1alpha1.ApplicationStatus{ + Health: v1alpha1.HealthStatus{ + Status: "Healthy", + }, + }}, + }, + enableProgressiveSyncs: true, + }, want: true}, + {name: "ApplicationSyncStatusDiff", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.Application{Status: v1alpha1.ApplicationStatus{ + Sync: v1alpha1.SyncStatus{ + Status: "OutOfSync", + }, + }}, + ObjectNew: &v1alpha1.Application{Status: v1alpha1.ApplicationStatus{ + Sync: v1alpha1.SyncStatus{ + Status: "Synced", + }, + }}, + }, + enableProgressiveSyncs: true, + }, want: true}, + {name: "ApplicationOperationStateDiff", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.Application{Status: v1alpha1.ApplicationStatus{ + OperationState: &v1alpha1.OperationState{ + Phase: "foo", + }, + }}, + ObjectNew: &v1alpha1.Application{Status: v1alpha1.ApplicationStatus{ + OperationState: &v1alpha1.OperationState{ + Phase: "bar", + }, + }}, + }, + enableProgressiveSyncs: true, + }, want: true}, + {name: "ApplicationOperationStartedAtDiff", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.Application{Status: v1alpha1.ApplicationStatus{ + OperationState: &v1alpha1.OperationState{ + StartedAt: now, + }, + }}, + ObjectNew: &v1alpha1.Application{Status: v1alpha1.ApplicationStatus{ + OperationState: &v1alpha1.OperationState{ + StartedAt: metav1.NewTime(now.Add(time.Minute * 1)), + }, + }}, + }, + enableProgressiveSyncs: true, + }, want: true}, + {name: "SameApplicationGeneration", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{ + Generation: 1, + }}, + ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{ + Generation: 2, + }}, + }}, want: false}, + {name: "DifferentApplicationSpec", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.Application{Spec: v1alpha1.ApplicationSpec{Project: "default"}}, + ObjectNew: &v1alpha1.Application{Spec: v1alpha1.ApplicationSpec{Project: "not-default"}}, + }}, want: true}, + {name: "DifferentApplicationLabels", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}}}, + ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"bar": "foo"}}}, + }}, want: true}, + {name: "DifferentApplicationAnnotations", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"foo": "bar"}}}, + ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{"bar": "foo"}}}, + }}, want: true}, + {name: "DifferentApplicationFinalizers", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"argo"}}}, + ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Finalizers: []string{"none"}}}, + }}, want: true}, + {name: "NotAnAppOld", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.AppProject{}, + ObjectNew: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"bar": "foo"}}}, + }}, want: false}, + {name: "NotAnAppNew", args: args{e: event.UpdateEvent{ + ObjectOld: &v1alpha1.Application{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"foo": "bar"}}}, + ObjectNew: &v1alpha1.AppProject{}, + }}, want: false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ownsHandler = getOwnsHandlerPredicates(tt.args.enableProgressiveSyncs) + assert.Equalf(t, tt.want, ownsHandler.UpdateFunc(tt.args.e), "UpdateFunc(%v)", tt.args.e) + }) + } +} diff --git a/applicationset/controllers/clustereventhandler.go b/applicationset/controllers/clustereventhandler.go index eb487b7f20076..951da0cb6bc44 100644 --- a/applicationset/controllers/clustereventhandler.go +++ b/applicationset/controllers/clustereventhandler.go @@ -2,6 +2,7 @@ package controllers import ( "context" + "fmt" log "github.com/sirupsen/logrus" @@ -46,7 +47,6 @@ type addRateLimitingInterface interface { } func (h *clusterSecretEventHandler) queueRelatedAppGenerators(q addRateLimitingInterface, object client.Object) { - // Check for label, lookup all ApplicationSets that might match the cluster, queue them all if object.GetLabels()[generators.ArgoCDSecretTypeLabel] != generators.ArgoCDSecretTypeCluster { return @@ -73,6 +73,40 @@ func (h *clusterSecretEventHandler) queueRelatedAppGenerators(q addRateLimitingI foundClusterGenerator = true break } + + if generator.Matrix != nil { + ok, err := nestedGeneratorsHaveClusterGenerator(generator.Matrix.Generators) + if err != nil { + h.Log. + WithFields(log.Fields{ + "namespace": appSet.GetNamespace(), + "name": appSet.GetName(), + }). + WithError(err). + Error("Unable to check if ApplicationSet matrix generators have cluster generator") + } + if ok { + foundClusterGenerator = true + break + } + } + + if generator.Merge != nil { + ok, err := nestedGeneratorsHaveClusterGenerator(generator.Merge.Generators) + if err != nil { + h.Log. + WithFields(log.Fields{ + "namespace": appSet.GetNamespace(), + "name": appSet.GetName(), + }). + WithError(err). + Error("Unable to check if ApplicationSet merge generators have cluster generator") + } + if ok { + foundClusterGenerator = true + break + } + } } if foundClusterGenerator { @@ -82,3 +116,50 @@ func (h *clusterSecretEventHandler) queueRelatedAppGenerators(q addRateLimitingI } } } + +// nestedGeneratorsHaveClusterGenerator iterate over provided nested generators to check if they have a cluster generator. +func nestedGeneratorsHaveClusterGenerator(generators []argoprojiov1alpha1.ApplicationSetNestedGenerator) (bool, error) { + for _, generator := range generators { + if ok, err := nestedGeneratorHasClusterGenerator(generator); ok || err != nil { + return ok, err + } + } + return false, nil +} + +// nestedGeneratorHasClusterGenerator checks if the provided generator has a cluster generator. +func nestedGeneratorHasClusterGenerator(nested argoprojiov1alpha1.ApplicationSetNestedGenerator) (bool, error) { + if nested.Clusters != nil { + return true, nil + } + + if nested.Matrix != nil { + nestedMatrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(nested.Matrix) + if err != nil { + return false, fmt.Errorf("unable to get nested matrix generator: %w", err) + } + if nestedMatrix != nil { + hasClusterGenerator, err := nestedGeneratorsHaveClusterGenerator(nestedMatrix.ToMatrixGenerator().Generators) + if err != nil { + return false, fmt.Errorf("error evaluating nested matrix generator: %w", err) + } + return hasClusterGenerator, nil + } + } + + if nested.Merge != nil { + nestedMerge, err := argoprojiov1alpha1.ToNestedMergeGenerator(nested.Merge) + if err != nil { + return false, fmt.Errorf("unable to get nested merge generator: %w", err) + } + if nestedMerge != nil { + hasClusterGenerator, err := nestedGeneratorsHaveClusterGenerator(nestedMerge.ToMergeGenerator().Generators) + if err != nil { + return false, fmt.Errorf("error evaluating nested merge generator: %w", err) + } + return hasClusterGenerator, nil + } + } + + return false, nil +} diff --git a/applicationset/controllers/clustereventhandler_test.go b/applicationset/controllers/clustereventhandler_test.go index 56fdd4b1974b8..7e850fc44c66d 100644 --- a/applicationset/controllers/clustereventhandler_test.go +++ b/applicationset/controllers/clustereventhandler_test.go @@ -6,6 +6,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" @@ -163,7 +164,6 @@ func TestClusterEventHandler(t *testing.T) { {NamespacedName: types.NamespacedName{Namespace: "another-namespace", Name: "my-app-set"}}, }, }, - { name: "non-argo cd secret should not match", items: []argov1alpha1.ApplicationSet{ @@ -189,6 +189,348 @@ func TestClusterEventHandler(t *testing.T) { }, expectedRequests: []reconcile.Request{}, }, + { + name: "a matrix generator with a cluster generator should produce a request", + items: []argov1alpha1.ApplicationSet{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "my-app-set", + Namespace: "argocd", + }, + Spec: argov1alpha1.ApplicationSetSpec{ + Generators: []argov1alpha1.ApplicationSetGenerator{ + { + Matrix: &argov1alpha1.MatrixGenerator{ + Generators: []argov1alpha1.ApplicationSetNestedGenerator{ + { + Clusters: &argov1alpha1.ClusterGenerator{}, + }, + }, + }, + }, + }, + }, + }, + }, + secret: corev1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "argocd", + Name: "my-secret", + Labels: map[string]string{ + generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, + }, + }, + }, + expectedRequests: []reconcile.Request{{ + NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"}, + }}, + }, + { + name: "a matrix generator with non cluster generator should not match", + items: []argov1alpha1.ApplicationSet{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "my-app-set", + Namespace: "argocd", + }, + Spec: argov1alpha1.ApplicationSetSpec{ + Generators: []argov1alpha1.ApplicationSetGenerator{ + { + Matrix: &argov1alpha1.MatrixGenerator{ + Generators: []argov1alpha1.ApplicationSetNestedGenerator{ + { + List: &argov1alpha1.ListGenerator{}, + }, + }, + }, + }, + }, + }, + }, + }, + secret: corev1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "argocd", + Name: "my-secret", + Labels: map[string]string{ + generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, + }, + }, + }, + expectedRequests: []reconcile.Request{}, + }, + { + name: "a matrix generator with a nested matrix generator containing a cluster generator should produce a request", + items: []argov1alpha1.ApplicationSet{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "my-app-set", + Namespace: "argocd", + }, + Spec: argov1alpha1.ApplicationSetSpec{ + Generators: []argov1alpha1.ApplicationSetGenerator{ + { + Matrix: &argov1alpha1.MatrixGenerator{ + Generators: []argov1alpha1.ApplicationSetNestedGenerator{ + { + Matrix: &apiextensionsv1.JSON{ + Raw: []byte( + `{ + "generators": [ + { + "clusters": { + "selector": { + "matchLabels": { + "argocd.argoproj.io/secret-type": "cluster" + } + } + } + } + ] + }`, + ), + }, + }, + }, + }, + }, + }, + }, + }, + }, + secret: corev1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "argocd", + Name: "my-secret", + Labels: map[string]string{ + generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, + }, + }, + }, + expectedRequests: []reconcile.Request{{ + NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"}, + }}, + }, + { + name: "a matrix generator with a nested matrix generator containing non cluster generator should not match", + items: []argov1alpha1.ApplicationSet{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "my-app-set", + Namespace: "argocd", + }, + Spec: argov1alpha1.ApplicationSetSpec{ + Generators: []argov1alpha1.ApplicationSetGenerator{ + { + Matrix: &argov1alpha1.MatrixGenerator{ + Generators: []argov1alpha1.ApplicationSetNestedGenerator{ + { + Matrix: &apiextensionsv1.JSON{ + Raw: []byte( + `{ + "generators": [ + { + "list": { + "elements": [ + "a", + "b" + ] + } + } + ] + }`, + ), + }, + }, + }, + }, + }, + }, + }, + }, + }, + secret: corev1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "argocd", + Name: "my-secret", + Labels: map[string]string{ + generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, + }, + }, + }, + expectedRequests: []reconcile.Request{}, + }, + { + name: "a merge generator with a cluster generator should produce a request", + items: []argov1alpha1.ApplicationSet{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "my-app-set", + Namespace: "argocd", + }, + Spec: argov1alpha1.ApplicationSetSpec{ + Generators: []argov1alpha1.ApplicationSetGenerator{ + { + Merge: &argov1alpha1.MergeGenerator{ + Generators: []argov1alpha1.ApplicationSetNestedGenerator{ + { + Clusters: &argov1alpha1.ClusterGenerator{}, + }, + }, + }, + }, + }, + }, + }, + }, + secret: corev1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "argocd", + Name: "my-secret", + Labels: map[string]string{ + generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, + }, + }, + }, + expectedRequests: []reconcile.Request{{ + NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"}, + }}, + }, + { + name: "a matrix generator with non cluster generator should not match", + items: []argov1alpha1.ApplicationSet{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "my-app-set", + Namespace: "argocd", + }, + Spec: argov1alpha1.ApplicationSetSpec{ + Generators: []argov1alpha1.ApplicationSetGenerator{ + { + Merge: &argov1alpha1.MergeGenerator{ + Generators: []argov1alpha1.ApplicationSetNestedGenerator{ + { + List: &argov1alpha1.ListGenerator{}, + }, + }, + }, + }, + }, + }, + }, + }, + secret: corev1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "argocd", + Name: "my-secret", + Labels: map[string]string{ + generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, + }, + }, + }, + expectedRequests: []reconcile.Request{}, + }, + { + name: "a merge generator with a nested merge generator containing a cluster generator should produce a request", + items: []argov1alpha1.ApplicationSet{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "my-app-set", + Namespace: "argocd", + }, + Spec: argov1alpha1.ApplicationSetSpec{ + Generators: []argov1alpha1.ApplicationSetGenerator{ + { + Merge: &argov1alpha1.MergeGenerator{ + Generators: []argov1alpha1.ApplicationSetNestedGenerator{ + { + Merge: &apiextensionsv1.JSON{ + Raw: []byte( + `{ + "generators": [ + { + "clusters": { + "selector": { + "matchLabels": { + "argocd.argoproj.io/secret-type": "cluster" + } + } + } + } + ] + }`, + ), + }, + }, + }, + }, + }, + }, + }, + }, + }, + secret: corev1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "argocd", + Name: "my-secret", + Labels: map[string]string{ + generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, + }, + }, + }, + expectedRequests: []reconcile.Request{{ + NamespacedName: types.NamespacedName{Namespace: "argocd", Name: "my-app-set"}, + }}, + }, + { + name: "a merge generator with a nested merge generator containing non cluster generator should not match", + items: []argov1alpha1.ApplicationSet{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "my-app-set", + Namespace: "argocd", + }, + Spec: argov1alpha1.ApplicationSetSpec{ + Generators: []argov1alpha1.ApplicationSetGenerator{ + { + Merge: &argov1alpha1.MergeGenerator{ + Generators: []argov1alpha1.ApplicationSetNestedGenerator{ + { + Merge: &apiextensionsv1.JSON{ + Raw: []byte( + `{ + "generators": [ + { + "list": { + "elements": [ + "a", + "b" + ] + } + } + ] + }`, + ), + }, + }, + }, + }, + }, + }, + }, + }, + }, + secret: corev1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Namespace: "argocd", + Name: "my-secret", + Labels: map[string]string{ + generators.ArgoCDSecretTypeLabel: generators.ArgoCDSecretTypeCluster, + }, + }, + }, + expectedRequests: []reconcile.Request{}, + }, } for _, test := range tests { @@ -231,3 +573,68 @@ type mockAddRateLimitingInterface struct { errorOccurred bool addedItems []ctrl.Request } + +func TestNestedGeneratorHasClusterGenerator_NestedClusterGenerator(t *testing.T) { + nested := argov1alpha1.ApplicationSetNestedGenerator{ + Clusters: &argov1alpha1.ClusterGenerator{}, + } + + hasClusterGenerator, err := nestedGeneratorHasClusterGenerator(nested) + + assert.Nil(t, err) + assert.True(t, hasClusterGenerator) +} + +func TestNestedGeneratorHasClusterGenerator_NestedMergeGenerator(t *testing.T) { + nested := argov1alpha1.ApplicationSetNestedGenerator{ + Merge: &apiextensionsv1.JSON{ + Raw: []byte( + `{ + "generators": [ + { + "clusters": { + "selector": { + "matchLabels": { + "argocd.argoproj.io/secret-type": "cluster" + } + } + } + } + ] + }`, + ), + }, + } + + hasClusterGenerator, err := nestedGeneratorHasClusterGenerator(nested) + + assert.Nil(t, err) + assert.True(t, hasClusterGenerator) +} + +func TestNestedGeneratorHasClusterGenerator_NestedMergeGeneratorWithInvalidJSON(t *testing.T) { + nested := argov1alpha1.ApplicationSetNestedGenerator{ + Merge: &apiextensionsv1.JSON{ + Raw: []byte( + `{ + "generators": [ + { + "clusters": { + "selector": { + "matchLabels": { + "argocd.argoproj.io/secret-type": "cluster" + } + } + } + } + ] + `, + ), + }, + } + + hasClusterGenerator, err := nestedGeneratorHasClusterGenerator(nested) + + assert.NotNil(t, err) + assert.False(t, hasClusterGenerator) +} diff --git a/applicationset/controllers/requeue_after_test.go b/applicationset/controllers/requeue_after_test.go new file mode 100644 index 0000000000000..6db6145af5348 --- /dev/null +++ b/applicationset/controllers/requeue_after_test.go @@ -0,0 +1,153 @@ +package controllers + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + dynfake "k8s.io/client-go/dynamic/fake" + kubefake "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/tools/record" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/argoproj/argo-cd/v2/applicationset/generators" + "github.com/argoproj/argo-cd/v2/applicationset/services/mocks" + argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" +) + +func TestRequeueAfter(t *testing.T) { + mockServer := &mocks.Repos{} + ctx := context.Background() + scheme := runtime.NewScheme() + err := argov1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + gvrToListKind := map[schema.GroupVersionResource]string{{ + Group: "mallard.io", + Version: "v1", + Resource: "ducks", + }: "DuckList"} + appClientset := kubefake.NewSimpleClientset() + k8sClient := fake.NewClientBuilder().Build() + duckType := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "v2quack", + "kind": "Duck", + "metadata": map[string]interface{}{ + "name": "mightyduck", + "namespace": "namespace", + "labels": map[string]interface{}{"duck": "all-species"}, + }, + "status": map[string]interface{}{ + "decisions": []interface{}{ + map[string]interface{}{ + "clusterName": "staging-01", + }, + map[string]interface{}{ + "clusterName": "production-01", + }, + }, + }, + }, + } + fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, duckType) + + terminalGenerators := map[string]generators.Generator{ + "List": generators.NewListGenerator(), + "Clusters": generators.NewClusterGenerator(k8sClient, ctx, appClientset, "argocd"), + "Git": generators.NewGitGenerator(mockServer), + "SCMProvider": generators.NewSCMProviderGenerator(fake.NewClientBuilder().WithObjects(&corev1.Secret{}).Build(), generators.SCMAuthProviders{}, "", []string{""}, true), + "ClusterDecisionResource": generators.NewDuckTypeGenerator(ctx, fakeDynClient, appClientset, "argocd"), + "PullRequest": generators.NewPullRequestGenerator(k8sClient, generators.SCMAuthProviders{}, "", []string{""}, true), + } + + nestedGenerators := map[string]generators.Generator{ + "List": terminalGenerators["List"], + "Clusters": terminalGenerators["Clusters"], + "Git": terminalGenerators["Git"], + "SCMProvider": terminalGenerators["SCMProvider"], + "ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"], + "PullRequest": terminalGenerators["PullRequest"], + "Matrix": generators.NewMatrixGenerator(terminalGenerators), + "Merge": generators.NewMergeGenerator(terminalGenerators), + } + + topLevelGenerators := map[string]generators.Generator{ + "List": terminalGenerators["List"], + "Clusters": terminalGenerators["Clusters"], + "Git": terminalGenerators["Git"], + "SCMProvider": terminalGenerators["SCMProvider"], + "ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"], + "PullRequest": terminalGenerators["PullRequest"], + "Matrix": generators.NewMatrixGenerator(nestedGenerators), + "Merge": generators.NewMergeGenerator(nestedGenerators), + } + + client := fake.NewClientBuilder().WithScheme(scheme).Build() + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Recorder: record.NewFakeRecorder(0), + Generators: topLevelGenerators, + } + + type args struct { + appset *argov1alpha1.ApplicationSet + } + tests := []struct { + name string + args args + want time.Duration + wantErr assert.ErrorAssertionFunc + }{ + {name: "Cluster", args: args{appset: &argov1alpha1.ApplicationSet{ + Spec: argov1alpha1.ApplicationSetSpec{ + Generators: []argov1alpha1.ApplicationSetGenerator{{Clusters: &argov1alpha1.ClusterGenerator{}}}, + }, + }}, want: generators.NoRequeueAfter, wantErr: assert.NoError}, + {name: "ClusterMergeNested", args: args{&argov1alpha1.ApplicationSet{ + Spec: argov1alpha1.ApplicationSetSpec{ + Generators: []argov1alpha1.ApplicationSetGenerator{ + {Clusters: &argov1alpha1.ClusterGenerator{}}, + {Merge: &argov1alpha1.MergeGenerator{ + Generators: []argov1alpha1.ApplicationSetNestedGenerator{ + { + Clusters: &argov1alpha1.ClusterGenerator{}, + Git: &argov1alpha1.GitGenerator{}, + }, + }, + }}, + }, + }, + }}, want: generators.DefaultRequeueAfterSeconds, wantErr: assert.NoError}, + {name: "ClusterMatrixNested", args: args{&argov1alpha1.ApplicationSet{ + Spec: argov1alpha1.ApplicationSetSpec{ + Generators: []argov1alpha1.ApplicationSetGenerator{ + {Clusters: &argov1alpha1.ClusterGenerator{}}, + {Matrix: &argov1alpha1.MatrixGenerator{ + Generators: []argov1alpha1.ApplicationSetNestedGenerator{ + { + Clusters: &argov1alpha1.ClusterGenerator{}, + Git: &argov1alpha1.GitGenerator{}, + }, + }, + }}, + }, + }, + }}, want: generators.DefaultRequeueAfterSeconds, wantErr: assert.NoError}, + {name: "ListGenerator", args: args{appset: &argov1alpha1.ApplicationSet{ + Spec: argov1alpha1.ApplicationSetSpec{ + Generators: []argov1alpha1.ApplicationSetGenerator{{List: &argov1alpha1.ListGenerator{}}}, + }, + }}, want: generators.NoRequeueAfter, wantErr: assert.NoError}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, r.getMinRequeueAfter(tt.args.appset), "getMinRequeueAfter(%v)", tt.args.appset) + }) + } +} 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/examples/applications-sync-policies/create-only.yaml b/applicationset/examples/applications-sync-policies/create-only.yaml new file mode 100644 index 0000000000000..7758a70b45765 --- /dev/null +++ b/applicationset/examples/applications-sync-policies/create-only.yaml @@ -0,0 +1,35 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: guestbook +spec: + goTemplate: true + generators: + - list: + elements: + - cluster: engineering-dev + url: https://kubernetes.default.svc + foo: bar + # Update foo value with foo: bar + # Application engineering-prod-guestbook labels will still be baz + # Delete this element + # Application engineering-prod-guestbook will be kept + - cluster: engineering-prod + url: https://kubernetes.default.svc + foo: baz + template: + metadata: + name: '{{.cluster}}-guestbook' + labels: + foo: '{{.foo}}' + spec: + project: default + source: + repoURL: https://github.com/argoproj/argo-cd.git + targetRevision: HEAD + path: applicationset/examples/list-generator/guestbook/{{.cluster}} + destination: + server: '{{.url}}' + namespace: guestbook + syncPolicy: + applicationsSync: create-only diff --git a/applicationset/examples/applications-sync-policies/create-update.yaml b/applicationset/examples/applications-sync-policies/create-update.yaml new file mode 100644 index 0000000000000..277e8d6e18884 --- /dev/null +++ b/applicationset/examples/applications-sync-policies/create-update.yaml @@ -0,0 +1,35 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: guestbook +spec: + goTemplate: true + generators: + - list: + elements: + - cluster: engineering-dev + url: https://kubernetes.default.svc + foo: bar + # Update foo value with foo: bar + # Application engineering-prod-guestbook labels will change to foo: bar + # Delete this element + # Application engineering-prod-guestbook will be kept + - cluster: engineering-prod + url: https://kubernetes.default.svc + foo: baz + template: + metadata: + name: '{{.cluster}}-guestbook' + labels: + foo: '{{.foo}}' + spec: + project: default + source: + repoURL: https://github.com/argoproj/argo-cd.git + targetRevision: HEAD + path: applicationset/examples/list-generator/guestbook/{{.cluster}} + destination: + server: '{{.url}}' + namespace: guestbook + syncPolicy: + applicationsSync: create-update diff --git a/applicationset/examples/applications-sync-policies/guestbook/engineering-dev/guestbook-ui-deployment.yaml b/applicationset/examples/applications-sync-policies/guestbook/engineering-dev/guestbook-ui-deployment.yaml new file mode 100644 index 0000000000000..8a0975e363539 --- /dev/null +++ b/applicationset/examples/applications-sync-policies/guestbook/engineering-dev/guestbook-ui-deployment.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: guestbook-ui +spec: + replicas: 1 + revisionHistoryLimit: 3 + selector: + matchLabels: + app: guestbook-ui + template: + metadata: + labels: + app: guestbook-ui + spec: + containers: + - image: gcr.io/heptio-images/ks-guestbook-demo:0.2 + name: guestbook-ui + ports: + - containerPort: 80 diff --git a/applicationset/examples/applications-sync-policies/guestbook/engineering-dev/guestbook-ui-svc.yaml b/applicationset/examples/applications-sync-policies/guestbook/engineering-dev/guestbook-ui-svc.yaml new file mode 100644 index 0000000000000..e8a4a27fbae40 --- /dev/null +++ b/applicationset/examples/applications-sync-policies/guestbook/engineering-dev/guestbook-ui-svc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Service +metadata: + name: guestbook-ui +spec: + ports: + - port: 80 + targetPort: 80 + selector: + app: guestbook-ui diff --git a/applicationset/examples/applications-sync-policies/guestbook/engineering-prod/guestbook-ui-deployment.yaml b/applicationset/examples/applications-sync-policies/guestbook/engineering-prod/guestbook-ui-deployment.yaml new file mode 100644 index 0000000000000..8a0975e363539 --- /dev/null +++ b/applicationset/examples/applications-sync-policies/guestbook/engineering-prod/guestbook-ui-deployment.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: guestbook-ui +spec: + replicas: 1 + revisionHistoryLimit: 3 + selector: + matchLabels: + app: guestbook-ui + template: + metadata: + labels: + app: guestbook-ui + spec: + containers: + - image: gcr.io/heptio-images/ks-guestbook-demo:0.2 + name: guestbook-ui + ports: + - containerPort: 80 diff --git a/applicationset/examples/applications-sync-policies/guestbook/engineering-prod/guestbook-ui-svc.yaml b/applicationset/examples/applications-sync-policies/guestbook/engineering-prod/guestbook-ui-svc.yaml new file mode 100644 index 0000000000000..e8a4a27fbae40 --- /dev/null +++ b/applicationset/examples/applications-sync-policies/guestbook/engineering-prod/guestbook-ui-svc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Service +metadata: + name: guestbook-ui +spec: + ports: + - port: 80 + targetPort: 80 + selector: + app: guestbook-ui diff --git a/applicationset/examples/cluster/cluster-example.yaml b/applicationset/examples/cluster/cluster-example.yaml index 9714ce1952e9c..a8e54212595e8 100644 --- a/applicationset/examples/cluster/cluster-example.yaml +++ b/applicationset/examples/cluster/cluster-example.yaml @@ -4,6 +4,7 @@ metadata: name: guestbook spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - clusters: {} template: diff --git a/applicationset/examples/clusterDecisionResource/ducktype-example.yaml b/applicationset/examples/clusterDecisionResource/ducktype-example.yaml index c6058e870bbf6..cf633483a8f68 100644 --- a/applicationset/examples/clusterDecisionResource/ducktype-example.yaml +++ b/applicationset/examples/clusterDecisionResource/ducktype-example.yaml @@ -4,6 +4,7 @@ metadata: name: book-import spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - clusterDecisionResource: configMapRef: ocm-placement diff --git a/applicationset/examples/design-doc/applicationset.yaml b/applicationset/examples/design-doc/applicationset.yaml index b1e49bd814d15..7ab4e824596a3 100644 --- a/applicationset/examples/design-doc/applicationset.yaml +++ b/applicationset/examples/design-doc/applicationset.yaml @@ -8,6 +8,7 @@ metadata: name: guestbook spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - clusters: {} template: diff --git a/applicationset/examples/design-doc/git-directory-discovery.yaml b/applicationset/examples/design-doc/git-directory-discovery.yaml index 2f62e33cd6ca6..a158d034d9043 100644 --- a/applicationset/examples/design-doc/git-directory-discovery.yaml +++ b/applicationset/examples/design-doc/git-directory-discovery.yaml @@ -27,6 +27,7 @@ metadata: name: cluster-addons spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/infra-team/cluster-deployments.git diff --git a/applicationset/examples/design-doc/git-files-discovery.yaml b/applicationset/examples/design-doc/git-files-discovery.yaml index 3a4167886de69..367e318ac2d5a 100644 --- a/applicationset/examples/design-doc/git-files-discovery.yaml +++ b/applicationset/examples/design-doc/git-files-discovery.yaml @@ -38,6 +38,7 @@ metadata: name: guestbook spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/infra-team/cluster-deployments.git diff --git a/applicationset/examples/design-doc/git-files-literal.yaml b/applicationset/examples/design-doc/git-files-literal.yaml index 5cb9bd9553446..9dbace36e4c56 100644 --- a/applicationset/examples/design-doc/git-files-literal.yaml +++ b/applicationset/examples/design-doc/git-files-literal.yaml @@ -51,6 +51,7 @@ metadata: name: guestbook spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/infra-team/cluster-deployments.git diff --git a/applicationset/examples/design-doc/list.yaml b/applicationset/examples/design-doc/list.yaml index 3f76526b17df5..b1bcd593eac7f 100644 --- a/applicationset/examples/design-doc/list.yaml +++ b/applicationset/examples/design-doc/list.yaml @@ -5,6 +5,7 @@ metadata: name: guestbook spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - list: elements: diff --git a/applicationset/examples/design-doc/template-override.yaml b/applicationset/examples/design-doc/template-override.yaml index be55e739e15a2..970c7c395a820 100644 --- a/applicationset/examples/design-doc/template-override.yaml +++ b/applicationset/examples/design-doc/template-override.yaml @@ -8,6 +8,7 @@ metadata: name: guestbook spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - list: elements: diff --git a/applicationset/examples/git-generator-directory/excludes/git-directories-exclude-example.yaml b/applicationset/examples/git-generator-directory/excludes/git-directories-exclude-example.yaml index 786d30a536419..a021a3d0c66d3 100644 --- a/applicationset/examples/git-generator-directory/excludes/git-directories-exclude-example.yaml +++ b/applicationset/examples/git-generator-directory/excludes/git-directories-exclude-example.yaml @@ -5,6 +5,7 @@ metadata: namespace: argocd spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/argoproj/argo-cd.git diff --git a/applicationset/examples/git-generator-directory/git-directories-example.yaml b/applicationset/examples/git-generator-directory/git-directories-example.yaml index 4ac79a34dd43c..6fc16b4d39384 100644 --- a/applicationset/examples/git-generator-directory/git-directories-example.yaml +++ b/applicationset/examples/git-generator-directory/git-directories-example.yaml @@ -5,6 +5,7 @@ metadata: namespace: argocd spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/argoproj/argo-cd.git diff --git a/applicationset/examples/git-generator-files-discovery/git-generator-files.yaml b/applicationset/examples/git-generator-files-discovery/git-generator-files.yaml index 7ccd68f6c6b88..78a0136655498 100644 --- a/applicationset/examples/git-generator-files-discovery/git-generator-files.yaml +++ b/applicationset/examples/git-generator-files-discovery/git-generator-files.yaml @@ -4,6 +4,7 @@ metadata: name: guestbook spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/argoproj/argo-cd.git diff --git a/applicationset/examples/list-generator/list-elementsYaml-example.yaml b/applicationset/examples/list-generator/list-elementsYaml-example.yaml new file mode 100644 index 0000000000000..f3aa3f34dd57d --- /dev/null +++ b/applicationset/examples/list-generator/list-elementsYaml-example.yaml @@ -0,0 +1,14 @@ +key: + components: + - name: component1 + chart: podinfo + version: "6.3.2" + releaseName: component1 + repoUrl: "https://stefanprodan.github.io/podinfo" + namespace: component1 + - name: component2 + chart: podinfo + version: "6.3.3" + releaseName: component2 + repoUrl: "ghcr.io/stefanprodan/charts" + namespace: component2 diff --git a/applicationset/examples/list-generator/list-example.yaml b/applicationset/examples/list-generator/list-example.yaml index a54fa0cfd92e1..03e33130bad84 100644 --- a/applicationset/examples/list-generator/list-example.yaml +++ b/applicationset/examples/list-generator/list-example.yaml @@ -4,6 +4,7 @@ metadata: name: guestbook spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - list: elements: diff --git a/applicationset/examples/matrix/cluster-and-git.yaml b/applicationset/examples/matrix/cluster-and-git.yaml index a42568db821f3..d58d2fa5f83f6 100644 --- a/applicationset/examples/matrix/cluster-and-git.yaml +++ b/applicationset/examples/matrix/cluster-and-git.yaml @@ -8,6 +8,7 @@ metadata: name: cluster-git spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - matrix: generators: diff --git a/applicationset/examples/matrix/list-and-git.yaml b/applicationset/examples/matrix/list-and-git.yaml index d1a2979daedfe..9ba04345476b4 100644 --- a/applicationset/examples/matrix/list-and-git.yaml +++ b/applicationset/examples/matrix/list-and-git.yaml @@ -8,6 +8,7 @@ metadata: name: list-git spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - matrix: generators: diff --git a/applicationset/examples/matrix/list-and-list.yaml b/applicationset/examples/matrix/list-and-list.yaml index fe5606a4b4b53..f88189ba5ec01 100644 --- a/applicationset/examples/matrix/list-and-list.yaml +++ b/applicationset/examples/matrix/list-and-list.yaml @@ -5,6 +5,7 @@ metadata: namespace: argocd spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - matrix: generators: diff --git a/applicationset/examples/matrix/matrix-and-union-in-matrix.yaml b/applicationset/examples/matrix/matrix-and-union-in-matrix.yaml index 783b4c94b5c3a..e4fed589764a8 100644 --- a/applicationset/examples/matrix/matrix-and-union-in-matrix.yaml +++ b/applicationset/examples/matrix/matrix-and-union-in-matrix.yaml @@ -13,6 +13,7 @@ metadata: name: matrix-and-union-in-matrix spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - matrix: generators: diff --git a/applicationset/examples/merge/merge-clusters-and-list.yaml b/applicationset/examples/merge/merge-clusters-and-list.yaml index 48b35b0251ed4..c91f4fea47d7b 100644 --- a/applicationset/examples/merge/merge-clusters-and-list.yaml +++ b/applicationset/examples/merge/merge-clusters-and-list.yaml @@ -4,6 +4,7 @@ metadata: name: merge-clusters-and-list spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - merge: mergeKeys: diff --git a/applicationset/examples/merge/merge-two-matrixes.yaml b/applicationset/examples/merge/merge-two-matrixes.yaml index f7590fb685d9f..f864ac6948b2d 100644 --- a/applicationset/examples/merge/merge-two-matrixes.yaml +++ b/applicationset/examples/merge/merge-two-matrixes.yaml @@ -4,6 +4,7 @@ metadata: name: merge-two-matrixes spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - merge: mergeKeys: diff --git a/applicationset/examples/pull-request-generator/pull-request-example.yaml b/applicationset/examples/pull-request-generator/pull-request-example.yaml index 98f66ae095e6d..d8ad8502b9b13 100644 --- a/applicationset/examples/pull-request-generator/pull-request-example.yaml +++ b/applicationset/examples/pull-request-generator/pull-request-example.yaml @@ -4,6 +4,7 @@ metadata: name: myapp spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: github: diff --git a/applicationset/examples/scm-provider-generator/scm-provider-example-fasttemplate-gitlab.yaml b/applicationset/examples/scm-provider-generator/scm-provider-example-fasttemplate-gitlab.yaml new file mode 100644 index 0000000000000..c62c151122d1f --- /dev/null +++ b/applicationset/examples/scm-provider-generator/scm-provider-example-fasttemplate-gitlab.yaml @@ -0,0 +1,26 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: guestbook +spec: + generators: + - scmProvider: + gitlab: + api: https://gitlab.com + group: test-argocd-proton + includeSubgroups: true + cloneProtocol: https + filters: + - repositoryMatch: test-app + template: + metadata: + name: '{{ repository }}-guestbook' + spec: + project: "default" + source: + repoURL: '{{ url }}' + targetRevision: '{{ branch }}' + path: guestbook + destination: + server: https://kubernetes.default.svc + namespace: guestbook diff --git a/applicationset/examples/scm-provider-generator/scm-provider-example.yaml b/applicationset/examples/scm-provider-generator/scm-provider-example.yaml index 8e310d45ccda5..c3ca2e5b3e5a9 100644 --- a/applicationset/examples/scm-provider-generator/scm-provider-example.yaml +++ b/applicationset/examples/scm-provider-generator/scm-provider-example.yaml @@ -4,6 +4,7 @@ metadata: name: guestbook spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - scmProvider: github: diff --git a/applicationset/examples/template-override/template-overrides-example.yaml b/applicationset/examples/template-override/template-overrides-example.yaml index dbc19418b4716..48cbf703fcd70 100644 --- a/applicationset/examples/template-override/template-overrides-example.yaml +++ b/applicationset/examples/template-override/template-overrides-example.yaml @@ -8,6 +8,7 @@ metadata: name: guestbook spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - list: elements: diff --git a/applicationset/generators/cluster.go b/applicationset/generators/cluster.go index d91ee3126279a..d8647d78d3a5c 100644 --- a/applicationset/generators/cluster.go +++ b/applicationset/generators/cluster.go @@ -51,6 +51,8 @@ func NewClusterGenerator(c client.Client, ctx context.Context, clientset kuberne return g } +// GetRequeueAfter never requeue the cluster generator because the `clusterSecretEventHandler` will requeue the appsets +// when the cluster secrets change func (g *ClusterGenerator) GetRequeueAfter(appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator) time.Duration { return NoRequeueAfter } @@ -59,8 +61,7 @@ func (g *ClusterGenerator) GetTemplate(appSetGenerator *argoappsetv1alpha1.Appli return &appSetGenerator.Clusters.Template } -func (g *ClusterGenerator) GenerateParams( - appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator, appSet *argoappsetv1alpha1.ApplicationSet) ([]map[string]interface{}, error) { +func (g *ClusterGenerator) GenerateParams(appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator, appSet *argoappsetv1alpha1.ApplicationSet) ([]map[string]interface{}, error) { if appSetGenerator == nil { return nil, EmptyAppSetGeneratorError @@ -77,7 +78,7 @@ func (g *ClusterGenerator) GenerateParams( // ListCluster from Argo CD's util/db package will include the local cluster in the list of clusters clustersFromArgoCD, err := utils.ListClusters(g.ctx, g.clientset, g.namespace) if err != nil { - return nil, err + return nil, fmt.Errorf("error listing clusters: %w", err) } if clustersFromArgoCD == nil { @@ -107,7 +108,7 @@ func (g *ClusterGenerator) GenerateParams( params["nameNormalized"] = cluster.Name params["server"] = cluster.Server - err = appendTemplatedValues(appSetGenerator.Clusters.Values, params, appSet) + err = appendTemplatedValues(appSetGenerator.Clusters.Values, params, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions) if err != nil { return nil, err } @@ -147,7 +148,7 @@ func (g *ClusterGenerator) GenerateParams( } } - err = appendTemplatedValues(appSetGenerator.Clusters.Values, params, appSet) + err = appendTemplatedValues(appSetGenerator.Clusters.Values, params, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions) if err != nil { return nil, err } @@ -160,44 +161,6 @@ func (g *ClusterGenerator) GenerateParams( return res, nil } -func appendTemplatedValues(clusterValues map[string]string, params map[string]interface{}, appSet *argoappsetv1alpha1.ApplicationSet) error { - // We create a local map to ensure that we do not fall victim to a billion-laughs attack. We iterate through the - // cluster values map and only replace values in said map if it has already been whitelisted in the params map. - // Once we iterate through all the cluster values we can then safely merge the `tmp` map into the main params map. - tmp := map[string]interface{}{} - - for key, value := range clusterValues { - result, err := replaceTemplatedString(value, params, appSet) - - if err != nil { - return fmt.Errorf("error replacing templated String: %w", err) - } - - if appSet.Spec.GoTemplate { - if tmp["values"] == nil { - tmp["values"] = map[string]string{} - } - tmp["values"].(map[string]string)[key] = result - } else { - tmp[fmt.Sprintf("values.%s", key)] = result - } - } - - for key, value := range tmp { - params[key] = value - } - - return nil -} - -func replaceTemplatedString(value string, params map[string]interface{}, appSet *argoappsetv1alpha1.ApplicationSet) (string, error) { - replacedTmplStr, err := render.Replace(value, params, appSet.Spec.GoTemplate) - if err != nil { - return "", err - } - return replacedTmplStr, nil -} - func (g *ClusterGenerator) getSecretsByClusterName(appSetGenerator *argoappsetv1alpha1.ApplicationSetGenerator) (map[string]corev1.Secret, error) { // List all Clusters: clusterSecretList := &corev1.SecretList{} diff --git a/applicationset/generators/duck_type.go b/applicationset/generators/duck_type.go index cdd13e8aeaf7a..f98afd0e01381 100644 --- a/applicationset/generators/duck_type.go +++ b/applicationset/generators/duck_type.go @@ -74,7 +74,7 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A // ListCluster from Argo CD's util/db package will include the local cluster in the list of clusters clustersFromArgoCD, err := utils.ListClusters(g.ctx, g.clientset, g.namespace) if err != nil { - return nil, err + return nil, fmt.Errorf("error listing clusters: %w", err) } if clustersFromArgoCD == nil { @@ -85,7 +85,7 @@ func (g *DuckTypeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.A cm, err := g.clientset.CoreV1().ConfigMaps(g.namespace).Get(g.ctx, appSetGenerator.ClusterDecisionResource.ConfigMapRef, metav1.GetOptions{}) if err != nil { - return nil, err + return nil, fmt.Errorf("error reading configMapRef: %w", err) } // Extract GVK data for the dynamic client to use diff --git a/applicationset/generators/duck_type_test.go b/applicationset/generators/duck_type_test.go index 21882e86575ed..788457b27559c 100644 --- a/applicationset/generators/duck_type_test.go +++ b/applicationset/generators/duck_type_test.go @@ -3,6 +3,7 @@ package generators import ( "context" "fmt" + "testing" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" @@ -15,8 +16,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - - "testing" ) const resourceApiVersion = "mallard.io/v1" diff --git a/applicationset/generators/generator_spec_processor.go b/applicationset/generators/generator_spec_processor.go index 4e08816e3e0c0..494b2e8d9a37d 100644 --- a/applicationset/generators/generator_spec_processor.go +++ b/applicationset/generators/generator_spec_processor.go @@ -2,12 +2,12 @@ package generators import ( "fmt" - "encoding/json" "reflect" + "github.com/jeremywohl/flatten" + "github.com/argoproj/argo-cd/v2/applicationset/utils" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" @@ -25,9 +25,12 @@ type TransformResult struct { Template argoprojiov1alpha1.ApplicationSetTemplate } -//Transform a spec generator to list of paramSets and a template +// Transform a spec generator to list of paramSets and a template func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, allGenerators map[string]Generator, baseTemplate argoprojiov1alpha1.ApplicationSetTemplate, appSet *argoprojiov1alpha1.ApplicationSet, genParams map[string]interface{}) ([]TransformResult, error) { - selector, err := metav1.LabelSelectorAsSelector(requestedGenerator.Selector) + // This is a custom version of the `LabelSelectorAsSelector` that is in k8s.io/apimachinery. This has been copied + // verbatim from that package, with the difference that we do not have any restrictions on label values. This is done + // so that, among other things, we can match on cluster urls. + selector, err := utils.LabelSelectorAsSelector(requestedGenerator.Selector) if err != nil { return nil, fmt.Errorf("error parsing label selector: %w", err) } @@ -50,7 +53,7 @@ func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, al } var params []map[string]interface{} if len(genParams) != 0 { - tempInterpolatedGenerator, err := InterpolateGenerator(&requestedGenerator, genParams, appSet.Spec.GoTemplate) + tempInterpolatedGenerator, err := InterpolateGenerator(&requestedGenerator, genParams, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions) interpolatedGenerator = &tempInterpolatedGenerator if err != nil { log.WithError(err).WithField("genParams", genParams). @@ -72,8 +75,17 @@ func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, al } var filterParams []map[string]interface{} for _, param := range params { + flatParam, err := flattenParameters(param) + if err != nil { + log.WithError(err).WithField("generator", g). + Error("error flattening params") + if firstError == nil { + firstError = err + } + continue + } - if requestedGenerator.Selector != nil && !selector.Matches(labels.Set(keepOnlyStringValues(param))) { + if requestedGenerator.Selector != nil && !selector.Matches(labels.Set(flatParam)) { continue } filterParams = append(filterParams, param) @@ -88,18 +100,6 @@ func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, al return res, firstError } -func keepOnlyStringValues(in map[string]interface{}) map[string]string { - var out map[string]string = map[string]string{} - - for key, value := range in { - if _, ok := value.(string); ok { - out[key] = value.(string) - } - } - - return out -} - func GetRelevantGenerators(requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, generators map[string]Generator) []Generator { var res []Generator @@ -122,6 +122,20 @@ func GetRelevantGenerators(requestedGenerator *argoprojiov1alpha1.ApplicationSet return res } +func flattenParameters(in map[string]interface{}) (map[string]string, error) { + flat, err := flatten.Flatten(in, "", flatten.DotStyle) + if err != nil { + return nil, fmt.Errorf("error flatenning parameters: %w", err) + } + + out := make(map[string]string, len(flat)) + for k, v := range flat { + out[k] = fmt.Sprintf("%v", v) + } + + return out, nil +} + func mergeGeneratorTemplate(g Generator, requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetTemplate argoprojiov1alpha1.ApplicationSetTemplate) (argoprojiov1alpha1.ApplicationSetTemplate, error) { // Make a copy of the value from `GetTemplate()` before merge, rather than copying directly into // the provided parameter (which will touch the original resource object returned by client-go) @@ -132,27 +146,28 @@ func mergeGeneratorTemplate(g Generator, requestedGenerator *argoprojiov1alpha1. return *dest, err } -// Currently for Matrix Generator. Allows interpolating the matrix's 2nd child generator with values from the 1st child generator +// InterpolateGenerator allows interpolating the matrix's 2nd child generator with values from the 1st child generator // "params" parameter is an array, where each index corresponds to a generator. Each index contains a map w/ that generator's parameters. -func InterpolateGenerator(requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, params map[string]interface{}, useGoTemplate bool) (argoprojiov1alpha1.ApplicationSetGenerator, error) { - interpolatedGenerator := requestedGenerator.DeepCopy() - tmplBytes, err := json.Marshal(interpolatedGenerator) - if err != nil { - log.WithError(err).WithField("requestedGenerator", interpolatedGenerator).Error("error marshalling requested generator for interpolation") - return *interpolatedGenerator, err - } - +func InterpolateGenerator(requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (argoprojiov1alpha1.ApplicationSetGenerator, error) { render := utils.Render{} - replacedTmplStr, err := render.Replace(string(tmplBytes), params, useGoTemplate) + interpolatedGenerator, err := render.RenderGeneratorParams(requestedGenerator, params, useGoTemplate, goTemplateOptions) if err != nil { - log.WithError(err).WithField("interpolatedGeneratorString", replacedTmplStr).Error("error interpolating generator with other generator's parameter") - return *interpolatedGenerator, err + log.WithError(err).WithField("interpolatedGenerator", interpolatedGenerator).Error("error interpolating generator with other generator's parameter") + return argoprojiov1alpha1.ApplicationSetGenerator{}, err } - err = json.Unmarshal([]byte(replacedTmplStr), interpolatedGenerator) - if err != nil { - log.WithError(err).WithField("requestedGenerator", interpolatedGenerator).Error("error unmarshalling requested generator for interpolation") - return *interpolatedGenerator, err - } return *interpolatedGenerator, nil } + +// Fixes https://github.com/argoproj/argo-cd/issues/11982 while ensuring backwards compatibility. +// This is only a short-term solution and should be removed in a future major version. +func dropDisabledNestedSelectors(generators []argoprojiov1alpha1.ApplicationSetNestedGenerator) bool { + var foundSelector bool + for i := range generators { + if generators[i].Selector != nil { + foundSelector = true + generators[i].Selector = nil + } + } + return foundSelector +} diff --git a/applicationset/generators/generator_spec_processor_test.go b/applicationset/generators/generator_spec_processor_test.go index 8dc125cac0d35..b5838e7af7cbe 100644 --- a/applicationset/generators/generator_spec_processor_test.go +++ b/applicationset/generators/generator_spec_processor_test.go @@ -6,9 +6,12 @@ import ( log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/argoproj/argo-cd/v2/applicationset/services/mocks" + argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/stretchr/testify/mock" @@ -17,8 +20,6 @@ import ( kubefake "k8s.io/client-go/kubernetes/fake" crtclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" - - argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) func TestMatchValues(t *testing.T) { @@ -69,16 +70,18 @@ func TestMatchValues(t *testing.T) { "List": listGenerator, } - applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ + applicationSetInfo := argov1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "set", }, - Spec: argoprojiov1alpha1.ApplicationSetSpec{}, + Spec: argov1alpha1.ApplicationSetSpec{ + GoTemplate: false, + }, } - results, err := Transform(argoprojiov1alpha1.ApplicationSetGenerator{ + results, err := Transform(argov1alpha1.ApplicationSetGenerator{ Selector: testCase.selector, - List: &argoprojiov1alpha1.ListGenerator{ + List: &argov1alpha1.ListGenerator{ Elements: testCase.elements, Template: emptyTemplate(), }}, @@ -92,8 +95,160 @@ func TestMatchValues(t *testing.T) { } } -func emptyTemplate() argoprojiov1alpha1.ApplicationSetTemplate { - return argoprojiov1alpha1.ApplicationSetTemplate{ +func TestMatchValuesGoTemplate(t *testing.T) { + testCases := []struct { + name string + elements []apiextensionsv1.JSON + selector *metav1.LabelSelector + expected []map[string]interface{} + }{ + { + name: "no filter", + elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}}, + selector: &metav1.LabelSelector{}, + expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}}, + }, + { + name: "nil", + elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}}, + selector: nil, + expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}}, + }, + { + name: "values.foo should be foo but is ignore element", + elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}}, + selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "values.foo": "foo", + }, + }, + expected: []map[string]interface{}{}, + }, + { + name: "values.foo should be bar", + elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}}, + selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "values.foo": "bar", + }, + }, + expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values": map[string]interface{}{"foo": "bar"}}}, + }, + { + name: "values.0 should be bar", + elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":["bar"]}`)}}, + selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "values.0": "bar", + }, + }, + expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values": []interface{}{"bar"}}}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + var listGenerator = NewListGenerator() + var data = map[string]Generator{ + "List": listGenerator, + } + + applicationSetInfo := argov1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "set", + }, + Spec: argov1alpha1.ApplicationSetSpec{ + GoTemplate: true, + }, + } + + results, err := Transform(argov1alpha1.ApplicationSetGenerator{ + Selector: testCase.selector, + List: &argov1alpha1.ListGenerator{ + Elements: testCase.elements, + Template: emptyTemplate(), + }}, + data, + emptyTemplate(), + &applicationSetInfo, nil) + + assert.NoError(t, err) + assert.ElementsMatch(t, testCase.expected, results[0].Params) + }) + } +} + +func TestTransForm(t *testing.T) { + testCases := []struct { + name string + selector *metav1.LabelSelector + expected []map[string]interface{} + }{ + { + name: "server filter", + selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"server": "https://production-01.example.com"}, + }, + expected: []map[string]interface{}{{ + "metadata.annotations.foo.argoproj.io": "production", + "metadata.labels.argocd.argoproj.io/secret-type": "cluster", + "metadata.labels.environment": "production", + "metadata.labels.org": "bar", + "name": "production_01/west", + "nameNormalized": "production-01-west", + "server": "https://production-01.example.com", + }}, + }, + { + name: "server filter with long url", + selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"server": "https://some-really-long-url-that-will-exceed-63-characters.com"}, + }, + expected: []map[string]interface{}{{ + "metadata.annotations.foo.argoproj.io": "production", + "metadata.labels.argocd.argoproj.io/secret-type": "cluster", + "metadata.labels.environment": "production", + "metadata.labels.org": "bar", + "name": "some-really-long-server-url", + "nameNormalized": "some-really-long-server-url", + "server": "https://some-really-long-url-that-will-exceed-63-characters.com", + }}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + testGenerators := map[string]Generator{ + "Clusters": getMockClusterGenerator(), + } + + applicationSetInfo := argov1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "set", + }, + Spec: argov1alpha1.ApplicationSetSpec{}, + } + + results, err := Transform( + argov1alpha1.ApplicationSetGenerator{ + Selector: testCase.selector, + Clusters: &argov1alpha1.ClusterGenerator{ + Selector: metav1.LabelSelector{}, + Template: argov1alpha1.ApplicationSetTemplate{}, + Values: nil, + }}, + testGenerators, + emptyTemplate(), + &applicationSetInfo, nil) + + assert.NoError(t, err) + assert.ElementsMatch(t, testCase.expected, results[0].Params) + }) + } +} + +func emptyTemplate() argov1alpha1.ApplicationSetTemplate { + return argov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", }, @@ -150,8 +305,35 @@ func getMockClusterGenerator() Generator { }, Type: corev1.SecretType("Opaque"), }, + &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + Kind: "Secret", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "some-really-long-server-url", + Namespace: "namespace", + Labels: map[string]string{ + "argocd.argoproj.io/secret-type": "cluster", + "environment": "production", + "org": "bar", + }, + Annotations: map[string]string{ + "foo.argoproj.io": "production", + }, + }, + Data: map[string][]byte{ + "config": []byte("{}"), + "name": []byte("some-really-long-server-url"), + "server": []byte("https://some-really-long-url-that-will-exceed-63-characters.com"), + }, + Type: corev1.SecretType("Opaque"), + }, } runtimeClusters := []runtime.Object{} + for _, clientCluster := range clusters { + runtimeClusters = append(runtimeClusters, clientCluster) + } appClientset := kubefake.NewSimpleClientset(runtimeClusters...) fakeClient := fake.NewClientBuilder().WithObjects(clusters...).Build() @@ -159,9 +341,9 @@ func getMockClusterGenerator() Generator { } func getMockGitGenerator() Generator { - argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}} - argoCDServiceMock.mock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return([]string{"app1", "app2", "app_3", "p1/app4"}, nil) - var gitGenerator = NewGitGenerator(argoCDServiceMock) + argoCDServiceMock := mocks.Repos{} + argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return([]string{"app1", "app2", "app_3", "p1/app4"}, nil) + var gitGenerator = NewGitGenerator(&argoCDServiceMock) return gitGenerator } @@ -176,8 +358,8 @@ func TestGetRelevantGenerators(t *testing.T) { testGenerators["Merge"] = NewMergeGenerator(testGenerators) testGenerators["List"] = NewListGenerator() - requestedGenerator := &argoprojiov1alpha1.ApplicationSetGenerator{ - List: &argoprojiov1alpha1.ListGenerator{ + requestedGenerator := &argov1alpha1.ApplicationSetGenerator{ + List: &argov1alpha1.ListGenerator{ Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}}, }} @@ -185,10 +367,10 @@ func TestGetRelevantGenerators(t *testing.T) { assert.Len(t, relevantGenerators, 1) assert.IsType(t, &ListGenerator{}, relevantGenerators[0]) - requestedGenerator = &argoprojiov1alpha1.ApplicationSetGenerator{ - Clusters: &argoprojiov1alpha1.ClusterGenerator{ + requestedGenerator = &argov1alpha1.ApplicationSetGenerator{ + Clusters: &argov1alpha1.ClusterGenerator{ Selector: metav1.LabelSelector{}, - Template: argoprojiov1alpha1.ApplicationSetTemplate{}, + Template: argov1alpha1.ApplicationSetTemplate{}, Values: nil, }, } @@ -197,14 +379,14 @@ func TestGetRelevantGenerators(t *testing.T) { assert.Len(t, relevantGenerators, 1) assert.IsType(t, &ClusterGenerator{}, relevantGenerators[0]) - requestedGenerator = &argoprojiov1alpha1.ApplicationSetGenerator{ - Git: &argoprojiov1alpha1.GitGenerator{ + requestedGenerator = &argov1alpha1.ApplicationSetGenerator{ + Git: &argov1alpha1.GitGenerator{ RepoURL: "", Directories: nil, Files: nil, Revision: "", RequeueAfterSeconds: nil, - Template: argoprojiov1alpha1.ApplicationSetTemplate{}, + Template: argov1alpha1.ApplicationSetTemplate{}, }, } @@ -214,8 +396,8 @@ func TestGetRelevantGenerators(t *testing.T) { } func TestInterpolateGenerator(t *testing.T) { - requestedGenerator := &argoprojiov1alpha1.ApplicationSetGenerator{ - Clusters: &argoprojiov1alpha1.ClusterGenerator{ + requestedGenerator := &argov1alpha1.ApplicationSetGenerator{ + Clusters: &argov1alpha1.ClusterGenerator{ Selector: metav1.LabelSelector{ MatchLabels: map[string]string{ "argocd.argoproj.io/secret-type": "cluster", @@ -232,7 +414,7 @@ func TestInterpolateGenerator(t *testing.T) { "path[1]": "p2", "path.basenameNormalized": "app3", } - interpolatedGenerator, err := InterpolateGenerator(requestedGenerator, gitGeneratorParams, false) + interpolatedGenerator, err := InterpolateGenerator(requestedGenerator, gitGeneratorParams, false, nil) if err != nil { log.WithError(err).WithField("requestedGenerator", requestedGenerator).Error("error interpolating Generator") return @@ -241,23 +423,23 @@ func TestInterpolateGenerator(t *testing.T) { assert.Equal(t, "p1", interpolatedGenerator.Clusters.Selector.MatchLabels["path-zero"]) assert.Equal(t, "p1/p2/app3", interpolatedGenerator.Clusters.Selector.MatchLabels["path-full"]) - fileNamePath := argoprojiov1alpha1.GitFileGeneratorItem{ + fileNamePath := argov1alpha1.GitFileGeneratorItem{ Path: "{{name}}", } - fileServerPath := argoprojiov1alpha1.GitFileGeneratorItem{ + fileServerPath := argov1alpha1.GitFileGeneratorItem{ Path: "{{server}}", } - requestedGenerator = &argoprojiov1alpha1.ApplicationSetGenerator{ - Git: &argoprojiov1alpha1.GitGenerator{ - Files: append([]argoprojiov1alpha1.GitFileGeneratorItem{}, fileNamePath, fileServerPath), - Template: argoprojiov1alpha1.ApplicationSetTemplate{}, + requestedGenerator = &argov1alpha1.ApplicationSetGenerator{ + Git: &argov1alpha1.GitGenerator{ + Files: append([]argov1alpha1.GitFileGeneratorItem{}, fileNamePath, fileServerPath), + Template: argov1alpha1.ApplicationSetTemplate{}, }, } clusterGeneratorParams := map[string]interface{}{ "name": "production_01/west", "server": "https://production-01.example.com", } - interpolatedGenerator, err = InterpolateGenerator(requestedGenerator, clusterGeneratorParams, true) + interpolatedGenerator, err = InterpolateGenerator(requestedGenerator, clusterGeneratorParams, false, nil) if err != nil { log.WithError(err).WithField("requestedGenerator", requestedGenerator).Error("error interpolating Generator") return @@ -265,3 +447,114 @@ func TestInterpolateGenerator(t *testing.T) { assert.Equal(t, "production_01/west", interpolatedGenerator.Git.Files[0].Path) assert.Equal(t, "https://production-01.example.com", interpolatedGenerator.Git.Files[1].Path) } + +func TestInterpolateGenerator_go(t *testing.T) { + requestedGenerator := &argov1alpha1.ApplicationSetGenerator{ + Clusters: &argov1alpha1.ClusterGenerator{ + Selector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "argocd.argoproj.io/secret-type": "cluster", + "path-basename": "{{base .path.path}}", + "path-zero": "{{index .path.segments 0}}", + "path-full": "{{.path.path}}", + "kubernetes.io/environment": `{{default "foo" .my_label}}`, + }}, + }, + } + gitGeneratorParams := map[string]interface{}{ + "path": map[string]interface{}{ + "path": "p1/p2/app3", + "segments": []string{"p1", "p2", "app3"}, + }, + } + interpolatedGenerator, err := InterpolateGenerator(requestedGenerator, gitGeneratorParams, true, nil) + require.NoError(t, err) + if err != nil { + log.WithError(err).WithField("requestedGenerator", requestedGenerator).Error("error interpolating Generator") + return + } + assert.Equal(t, "app3", interpolatedGenerator.Clusters.Selector.MatchLabels["path-basename"]) + assert.Equal(t, "p1", interpolatedGenerator.Clusters.Selector.MatchLabels["path-zero"]) + assert.Equal(t, "p1/p2/app3", interpolatedGenerator.Clusters.Selector.MatchLabels["path-full"]) + + fileNamePath := argov1alpha1.GitFileGeneratorItem{ + Path: "{{.name}}", + } + fileServerPath := argov1alpha1.GitFileGeneratorItem{ + Path: "{{.server}}", + } + + requestedGenerator = &argov1alpha1.ApplicationSetGenerator{ + Git: &argov1alpha1.GitGenerator{ + Files: append([]argov1alpha1.GitFileGeneratorItem{}, fileNamePath, fileServerPath), + Template: argov1alpha1.ApplicationSetTemplate{}, + }, + } + clusterGeneratorParams := map[string]interface{}{ + "name": "production_01/west", "server": "https://production-01.example.com", + } + interpolatedGenerator, err = InterpolateGenerator(requestedGenerator, clusterGeneratorParams, true, nil) + if err != nil { + log.WithError(err).WithField("requestedGenerator", requestedGenerator).Error("error interpolating Generator") + return + } + assert.Equal(t, "production_01/west", interpolatedGenerator.Git.Files[0].Path) + assert.Equal(t, "https://production-01.example.com", interpolatedGenerator.Git.Files[1].Path) +} + +func TestInterpolateGeneratorError(t *testing.T) { + type args struct { + requestedGenerator *argov1alpha1.ApplicationSetGenerator + params map[string]interface{} + useGoTemplate bool + goTemplateOptions []string + } + tests := []struct { + name string + args args + want argov1alpha1.ApplicationSetGenerator + expectedErrStr string + }{ + {name: "Empty Gen", args: args{ + requestedGenerator: nil, + params: nil, + useGoTemplate: false, + goTemplateOptions: nil, + }, want: argov1alpha1.ApplicationSetGenerator{}, expectedErrStr: "generator is empty"}, + {name: "No Params", args: args{ + requestedGenerator: &argov1alpha1.ApplicationSetGenerator{}, + params: map[string]interface{}{}, + useGoTemplate: false, + goTemplateOptions: nil, + }, want: argov1alpha1.ApplicationSetGenerator{}, expectedErrStr: ""}, + {name: "Error templating", args: args{ + requestedGenerator: &argov1alpha1.ApplicationSetGenerator{Git: &argov1alpha1.GitGenerator{ + RepoURL: "foo", + Files: []argov1alpha1.GitFileGeneratorItem{{Path: "bar/"}}, + Revision: "main", + Values: map[string]string{ + "git_test": "{{ toPrettyJson . }}", + "selection": "{{ default .override .test }}", + "resolved": "{{ index .rmap (default .override .test) }}", + }, + }}, + params: map[string]interface{}{ + "name": "in-cluster", + "override": "foo", + }, + useGoTemplate: true, + goTemplateOptions: []string{}, + }, want: argov1alpha1.ApplicationSetGenerator{}, expectedErrStr: "failed to replace parameters in generator: failed to execute go template {{ index .rmap (default .override .test) }}: template: :1:3: executing \"\" at : error calling index: index of untyped nil"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := InterpolateGenerator(tt.args.requestedGenerator, tt.args.params, tt.args.useGoTemplate, tt.args.goTemplateOptions) + if tt.expectedErrStr != "" { + assert.EqualError(t, err, tt.expectedErrStr) + } else { + require.NoError(t, err) + } + assert.Equalf(t, tt.want, got, "InterpolateGenerator(%v, %v, %v, %v)", tt.args.requestedGenerator, tt.args.params, tt.args.useGoTemplate, tt.args.goTemplateOptions) + }) + } +} diff --git a/applicationset/generators/git.go b/applicationset/generators/git.go index 7fd6d75fd6912..57fe2835b8df0 100644 --- a/applicationset/generators/git.go +++ b/applicationset/generators/git.go @@ -56,51 +56,56 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic return nil, EmptyAppSetGeneratorError } + noRevisionCache := appSet.RefreshRequired() + var err error var res []map[string]interface{} - if appSetGenerator.Git.Directories != nil { - res, err = g.generateParamsForGitDirectories(appSetGenerator, appSet.Spec.GoTemplate) - } else if appSetGenerator.Git.Files != nil { - res, err = g.generateParamsForGitFiles(appSetGenerator, appSet.Spec.GoTemplate) + if len(appSetGenerator.Git.Directories) != 0 { + res, err = g.generateParamsForGitDirectories(appSetGenerator, noRevisionCache, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions) + } else if len(appSetGenerator.Git.Files) != 0 { + res, err = g.generateParamsForGitFiles(appSetGenerator, noRevisionCache, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions) } else { return nil, EmptyAppSetGeneratorError } if err != nil { - return nil, err + return nil, fmt.Errorf("error generating params from git: %w", err) } return res, nil } -func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool) ([]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, err + return nil, fmt.Errorf("error getting directories from repo: %w", err) } log.WithFields(log.Fields{ - "allPaths": allPaths, - "total": len(allPaths), - "repoURL": appSetGenerator.Git.RepoURL, - "revision": appSetGenerator.Git.Revision, + "allPaths": allPaths, + "total": len(allPaths), + "repoURL": appSetGenerator.Git.RepoURL, + "revision": appSetGenerator.Git.Revision, "pathParamPrefix": appSetGenerator.Git.PathParamPrefix, }).Info("applications result from the repo service") requestedApps := g.filterApps(appSetGenerator.Git.Directories, allPaths) - res := g.generateParamsFromApps(requestedApps, appSetGenerator, useGoTemplate) + res, err := g.generateParamsFromApps(requestedApps, appSetGenerator, useGoTemplate, goTemplateOptions) + if err != nil { + return nil, fmt.Errorf("error generating params from apps: %w", err) + } return res, nil } -func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool) ([]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 } @@ -122,19 +127,17 @@ func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1al for _, path := range allPaths { // A JSON / YAML file path can contain multiple sets of parameters (ie it is an array) - paramsArray, err := g.generateParamsFromGitFile(path, allFiles[path], useGoTemplate, appSetGenerator.Git.PathParamPrefix) + paramsArray, err := g.generateParamsFromGitFile(path, allFiles[path], appSetGenerator.Git.Values, useGoTemplate, goTemplateOptions, appSetGenerator.Git.PathParamPrefix) if err != nil { return nil, fmt.Errorf("unable to process file '%s': %v", path, err) } - for index := range paramsArray { - res = append(res, paramsArray[index]) - } + res = append(res, paramsArray...) } return res, nil } -func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []byte, useGoTemplate bool, pathParamPrefix string) ([]map[string]interface{}, error) { +func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []byte, values map[string]string, useGoTemplate bool, goTemplateOptions []string, pathParamPrefix string) ([]map[string]interface{}, error) { objectsFound := []map[string]interface{}{} // First, we attempt to parse as an array @@ -147,6 +150,9 @@ func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent [] return nil, fmt.Errorf("unable to parse file: %v", err) } objectsFound = append(objectsFound, singleObj) + } else if len(objectsFound) == 0 { + // If file is valid but empty, add a default empty item + objectsFound = append(objectsFound, map[string]interface{}{}) } res := []map[string]interface{}{} @@ -176,14 +182,14 @@ func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent [] } else { flat, err := flatten.Flatten(objectFound, "", flatten.DotStyle) if err != nil { - return nil, err + return nil, fmt.Errorf("error flattening object: %w", err) } for k, v := range flat { params[k] = fmt.Sprintf("%v", v) } pathParamName := "path" if pathParamPrefix != "" { - pathParamName = pathParamPrefix+"."+pathParamName + pathParamName = pathParamPrefix + "." + pathParamName } params[pathParamName] = path.Dir(filePath) params[pathParamName+".basename"] = path.Base(params[pathParamName].(string)) @@ -197,6 +203,11 @@ func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent [] } } + err := appendTemplatedValues(values, params, useGoTemplate, goTemplateOptions) + if err != nil { + return nil, fmt.Errorf("failed to append templated values: %w", err) + } + res = append(res, params) } @@ -231,7 +242,7 @@ func (g *GitGenerator) filterApps(Directories []argoprojiov1alpha1.GitDirectoryG return res } -func (g *GitGenerator) generateParamsFromApps(requestedApps []string, appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool) []map[string]interface{} { +func (g *GitGenerator) generateParamsFromApps(requestedApps []string, appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool, goTemplateOptions []string) ([]map[string]interface{}, error) { res := make([]map[string]interface{}, len(requestedApps)) for i, a := range requestedApps { @@ -251,7 +262,7 @@ func (g *GitGenerator) generateParamsFromApps(requestedApps []string, appSetGene } else { pathParamName := "path" if appSetGenerator.Git.PathParamPrefix != "" { - pathParamName = appSetGenerator.Git.PathParamPrefix+"."+pathParamName + pathParamName = appSetGenerator.Git.PathParamPrefix + "." + pathParamName } params[pathParamName] = a params[pathParamName+".basename"] = path.Base(a) @@ -263,8 +274,13 @@ func (g *GitGenerator) generateParamsFromApps(requestedApps []string, appSetGene } } + err := appendTemplatedValues(appSetGenerator.Git.Values, params, useGoTemplate, goTemplateOptions) + if err != nil { + return nil, fmt.Errorf("failed to append templated values: %w", err) + } + res[i] = params } - return res + return res, nil } diff --git a/applicationset/generators/git_test.go b/applicationset/generators/git_test.go index 96cfe08404d81..d3fd4965057f8 100644 --- a/applicationset/generators/git_test.go +++ b/applicationset/generators/git_test.go @@ -1,152 +1,176 @@ package generators import ( - "context" "fmt" "testing" + "github.com/argoproj/argo-cd/v2/applicationset/services/mocks" + argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) -// type clientSet struct { -// RepoServerServiceClient apiclient.RepoServerServiceClient -// } - -// func (c *clientSet) NewRepoServerClient() (io.Closer, apiclient.RepoServerServiceClient, error) { -// return io.NewCloser(func() error { return nil }), c.RepoServerServiceClient, nil -// } - -type argoCDServiceMock struct { - mock *mock.Mock -} - -func (a argoCDServiceMock) GetApps(ctx context.Context, repoURL string, revision string) ([]string, error) { - args := a.mock.Called(ctx, repoURL, revision) - - return args.Get(0).([]string), args.Error(1) -} - -func (a argoCDServiceMock) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) { - args := a.mock.Called(ctx, repoURL, revision, pattern) - - return args.Get(0).(map[string][]byte), args.Error(1) -} - -func (a argoCDServiceMock) GetFileContent(ctx context.Context, repoURL string, revision string, path string) ([]byte, error) { - args := a.mock.Called(ctx, repoURL, revision, path) - - return args.Get(0).([]byte), args.Error(1) -} - -func (a argoCDServiceMock) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) { - args := a.mock.Called(ctx, repoURL, revision) - return args.Get(0).([]string), args.Error(1) -} - func Test_generateParamsFromGitFile(t *testing.T) { - params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(` + defaultContent := []byte(` foo: bar: baz -`), false, "") - if err != nil { - t.Fatal(err) +`) + type args struct { + filePath string + fileContent []byte + values map[string]string + useGoTemplate bool + goTemplateOptions []string + pathParamPrefix string } - assert.Equal(t, []map[string]interface{}{ + tests := []struct { + name string + args args + want []map[string]interface{} + wantErr bool + }{ { - "foo.bar": "baz", - "path": "path/dir", - "path.basename": "dir", - "path.filename": "file_name.yaml", - "path.basenameNormalized": "dir", - "path.filenameNormalized": "file-name.yaml", - "path[0]": "path", - "path[1]": "dir", + name: "empty file returns path parameters", + args: args{ + filePath: "path/dir/file_name.yaml", + fileContent: []byte(""), + values: map[string]string{}, + useGoTemplate: false, + }, + want: []map[string]interface{}{ + { + "path": "path/dir", + "path.basename": "dir", + "path.filename": "file_name.yaml", + "path.basenameNormalized": "dir", + "path.filenameNormalized": "file-name.yaml", + "path[0]": "path", + "path[1]": "dir", + }, + }, }, - }, params) -} - -func Test_generatePrefixedParamsFromGitFile(t *testing.T) { - params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(` -foo: - bar: baz -`), false, "myRepo") - if err != nil { - t.Fatal(err) - } - assert.Equal(t, []map[string]interface{}{ { - "foo.bar": "baz", - "myRepo.path": "path/dir", - "myRepo.path.basename": "dir", - "myRepo.path.filename": "file_name.yaml", - "myRepo.path.basenameNormalized": "dir", - "myRepo.path.filenameNormalized": "file-name.yaml", - "myRepo.path[0]": "path", - "myRepo.path[1]": "dir", + name: "invalid json/yaml file returns error", + args: args{ + filePath: "path/dir/file_name.yaml", + fileContent: []byte("this is not json or yaml"), + values: map[string]string{}, + useGoTemplate: false, + }, + wantErr: true, + }, + { + name: "file parameters are added to params", + args: args{ + filePath: "path/dir/file_name.yaml", + fileContent: defaultContent, + values: map[string]string{}, + useGoTemplate: false, + }, + want: []map[string]interface{}{ + { + "foo.bar": "baz", + "path": "path/dir", + "path.basename": "dir", + "path.filename": "file_name.yaml", + "path.basenameNormalized": "dir", + "path.filenameNormalized": "file-name.yaml", + "path[0]": "path", + "path[1]": "dir", + }, + }, }, - }, params) -} - -func Test_generateParamsFromGitFileGoTemplate(t *testing.T) { - params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(` -foo: - bar: baz -`), true, "") - if err != nil { - t.Fatal(err) - } - assert.Equal(t, []map[string]interface{}{ { - "foo": map[string]interface{}{ - "bar": "baz", + name: "path parameter are prefixed", + args: args{ + filePath: "path/dir/file_name.yaml", + fileContent: defaultContent, + values: map[string]string{}, + useGoTemplate: false, + pathParamPrefix: "myRepo", }, - "path": map[string]interface{}{ - "path": "path/dir", - "basename": "dir", - "filename": "file_name.yaml", - "basenameNormalized": "dir", - "filenameNormalized": "file-name.yaml", - "segments": []string{ - "path", - "dir", + want: []map[string]interface{}{ + { + "foo.bar": "baz", + "myRepo.path": "path/dir", + "myRepo.path.basename": "dir", + "myRepo.path.filename": "file_name.yaml", + "myRepo.path.basenameNormalized": "dir", + "myRepo.path.filenameNormalized": "file-name.yaml", + "myRepo.path[0]": "path", + "myRepo.path[1]": "dir", }, }, }, - }, params) -} - -func Test_generatePrefixedParamsFromGitFileGoTemplate(t *testing.T) { - params, err := (*GitGenerator)(nil).generateParamsFromGitFile("path/dir/file_name.yaml", []byte(` -foo: - bar: baz -`), true, "myRepo") - if err != nil { - t.Fatal(err) - } - assert.Equal(t, []map[string]interface{}{ { - "foo": map[string]interface{}{ - "bar": "baz", + name: "file parameters are added to params with go template", + args: args{ + filePath: "path/dir/file_name.yaml", + fileContent: defaultContent, + values: map[string]string{}, + useGoTemplate: true, }, - "myRepo": map[string]interface{}{ - "path": map[string]interface{}{ - "path": "path/dir", - "basename": "dir", - "filename": "file_name.yaml", - "basenameNormalized": "dir", - "filenameNormalized": "file-name.yaml", - "segments": []string{ - "path", - "dir", + want: []map[string]interface{}{ + { + "foo": map[string]interface{}{ + "bar": "baz", + }, + "path": map[string]interface{}{ + "path": "path/dir", + "basename": "dir", + "filename": "file_name.yaml", + "basenameNormalized": "dir", + "filenameNormalized": "file-name.yaml", + "segments": []string{ + "path", + "dir", + }, }, }, }, }, - }, params) + { + name: "path parameter are prefixed with go template", + args: args{ + filePath: "path/dir/file_name.yaml", + fileContent: defaultContent, + values: map[string]string{}, + useGoTemplate: true, + pathParamPrefix: "myRepo", + }, + want: []map[string]interface{}{ + { + "foo": map[string]interface{}{ + "bar": "baz", + }, + "myRepo": map[string]interface{}{ + "path": map[string]interface{}{ + "path": "path/dir", + "basename": "dir", + "filename": "file_name.yaml", + "basenameNormalized": "dir", + "filenameNormalized": "file-name.yaml", + "segments": []string{ + "path", + "dir", + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + params, err := (*GitGenerator)(nil).generateParamsFromGitFile(tt.args.filePath, tt.args.fileContent, tt.args.values, tt.args.useGoTemplate, tt.args.goTemplateOptions, tt.args.pathParamPrefix) + if (err != nil) != tt.wantErr { + t.Errorf("GitGenerator.generateParamsFromGitFile() error = %v, wantErr %v", err, tt.wantErr) + return + } + assert.Equal(t, tt.want, params) + }) + } } func TestGitGenerateParamsFromDirectories(t *testing.T) { @@ -157,6 +181,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) { pathParamPrefix string repoApps []string repoError error + values map[string]string expected []map[string]interface{} expectedError error }{ @@ -247,6 +272,25 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) { }, expectedError: nil, }, + { + name: "Value variable interpolation", + directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}, {Path: "*/*"}}, + repoApps: []string{ + "app1", + "p1/app2", + }, + repoError: nil, + values: map[string]string{ + "foo": "bar", + "aaa": "{{ path[0] }}", + "no-op": "{{ this-does-not-exist }}", + }, + expected: []map[string]interface{}{ + {"values.foo": "bar", "values.no-op": "{{ this-does-not-exist }}", "values.aaa": "app1", "path": "app1", "path.basename": "app1", "path[0]": "app1", "path.basenameNormalized": "app1"}, + {"values.foo": "bar", "values.no-op": "{{ this-does-not-exist }}", "values.aaa": "p1", "path": "p1/app2", "path.basename": "app2", "path[0]": "p1", "path[1]": "app2", "path.basenameNormalized": "app2"}, + }, + expectedError: nil, + }, { name: "handles empty response from repo server", directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{Path: "*"}}, @@ -261,7 +305,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) { repoApps: []string{}, repoError: fmt.Errorf("error"), expected: []map[string]interface{}{}, - expectedError: fmt.Errorf("error"), + expectedError: fmt.Errorf("error generating params from git: error getting directories from repo: error"), }, } @@ -271,11 +315,11 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) { t.Run(testCaseCopy.name, func(t *testing.T) { t.Parallel() - argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}} + argoCDServiceMock := mocks.Repos{} - argoCDServiceMock.mock.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) + var gitGenerator = NewGitGenerator(&argoCDServiceMock) applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "set", @@ -287,6 +331,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) { Revision: "Revision", Directories: testCaseCopy.directories, PathParamPrefix: testCaseCopy.pathParamPrefix, + Values: testCaseCopy.values, }, }}, }, @@ -301,7 +346,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) { assert.Equal(t, testCaseCopy.expected, got) } - argoCDServiceMock.mock.AssertExpectations(t) + argoCDServiceMock.AssertExpectations(t) }) } } @@ -556,7 +601,7 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) { repoApps: []string{}, repoError: fmt.Errorf("error"), expected: []map[string]interface{}{}, - expectedError: fmt.Errorf("error"), + expectedError: fmt.Errorf("error generating params from git: error getting directories from repo: error"), }, } @@ -566,11 +611,11 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) { t.Run(testCaseCopy.name, func(t *testing.T) { t.Parallel() - argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}} + argoCDServiceMock := mocks.Repos{} - argoCDServiceMock.mock.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) + var gitGenerator = NewGitGenerator(&argoCDServiceMock) applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "set", @@ -597,7 +642,7 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) { assert.Equal(t, testCaseCopy.expected, got) } - argoCDServiceMock.mock.AssertExpectations(t) + argoCDServiceMock.AssertExpectations(t) }) } @@ -613,6 +658,7 @@ func TestGitGenerateParamsFromFiles(t *testing.T) { repoFileContents map[string][]byte // if repoPathsError is non-nil, the call to GetPaths(...) will return this error value repoPathsError error + values map[string]string expected []map[string]interface{} expectedError error }{ @@ -676,13 +722,81 @@ func TestGitGenerateParamsFromFiles(t *testing.T) { }, expectedError: nil, }, + { + name: "Value variable interpolation", + files: []argoprojiov1alpha1.GitFileGeneratorItem{{Path: "**/config.json"}}, + repoFileContents: map[string][]byte{ + "cluster-config/production/config.json": []byte(`{ + "cluster": { + "owner": "john.doe@example.com", + "name": "production", + "address": "https://kubernetes.default.svc" + }, + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123 +}`), + "cluster-config/staging/config.json": []byte(`{ + "cluster": { + "owner": "foo.bar@example.com", + "name": "staging", + "address": "https://kubernetes.default.svc" + } +}`), + }, + repoPathsError: nil, + values: map[string]string{ + "aaa": "{{ cluster.owner }}", + "no-op": "{{ this-does-not-exist }}", + }, + expected: []map[string]interface{}{ + { + "cluster.owner": "john.doe@example.com", + "cluster.name": "production", + "cluster.address": "https://kubernetes.default.svc", + "key1": "val1", + "key2.key2_1": "val2_1", + "key2.key2_2.key2_2_1": "val2_2_1", + "key3": "123", + "path": "cluster-config/production", + "path.basename": "production", + "path[0]": "cluster-config", + "path[1]": "production", + "path.basenameNormalized": "production", + "path.filename": "config.json", + "path.filenameNormalized": "config.json", + "values.aaa": "john.doe@example.com", + "values.no-op": "{{ this-does-not-exist }}", + }, + { + "cluster.owner": "foo.bar@example.com", + "cluster.name": "staging", + "cluster.address": "https://kubernetes.default.svc", + "path": "cluster-config/staging", + "path.basename": "staging", + "path[0]": "cluster-config", + "path[1]": "staging", + "path.basenameNormalized": "staging", + "path.filename": "config.json", + "path.filenameNormalized": "config.json", + "values.aaa": "foo.bar@example.com", + "values.no-op": "{{ this-does-not-exist }}", + }, + }, + expectedError: nil, + }, { name: "handles error during getting repo paths", files: []argoprojiov1alpha1.GitFileGeneratorItem{{Path: "**/config.json"}}, repoFileContents: map[string][]byte{}, repoPathsError: fmt.Errorf("paths error"), expected: []map[string]interface{}{}, - expectedError: fmt.Errorf("paths error"), + expectedError: fmt.Errorf("error generating params from git: paths error"), }, { name: "test invalid JSON file returns error", @@ -692,7 +806,7 @@ func TestGitGenerateParamsFromFiles(t *testing.T) { }, repoPathsError: nil, expected: []map[string]interface{}{}, - expectedError: fmt.Errorf("unable to process file 'cluster-config/production/config.json': unable to parse file: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}"), + expectedError: fmt.Errorf("error generating params from git: unable to process file 'cluster-config/production/config.json': unable to parse file: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}"), }, { name: "test JSON array", @@ -857,11 +971,11 @@ cluster: t.Run(testCaseCopy.name, func(t *testing.T) { t.Parallel() - argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}} - argoCDServiceMock.mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + argoCDServiceMock := mocks.Repos{} + argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError) - var gitGenerator = NewGitGenerator(argoCDServiceMock) + var gitGenerator = NewGitGenerator(&argoCDServiceMock) applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "set", @@ -872,6 +986,7 @@ cluster: RepoURL: "RepoURL", Revision: "Revision", Files: testCaseCopy.files, + Values: testCaseCopy.values, }, }}, }, @@ -887,7 +1002,7 @@ cluster: assert.ElementsMatch(t, testCaseCopy.expected, got) } - argoCDServiceMock.mock.AssertExpectations(t) + argoCDServiceMock.AssertExpectations(t) }) } } @@ -987,7 +1102,7 @@ func TestGitGenerateParamsFromFilesGoTemplate(t *testing.T) { repoFileContents: map[string][]byte{}, repoPathsError: fmt.Errorf("paths error"), expected: []map[string]interface{}{}, - expectedError: fmt.Errorf("paths error"), + expectedError: fmt.Errorf("error generating params from git: paths error"), }, { name: "test invalid JSON file returns error", @@ -997,7 +1112,7 @@ func TestGitGenerateParamsFromFilesGoTemplate(t *testing.T) { }, repoPathsError: nil, expected: []map[string]interface{}{}, - expectedError: fmt.Errorf("unable to process file 'cluster-config/production/config.json': unable to parse file: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}"), + expectedError: fmt.Errorf("error generating params from git: unable to process file 'cluster-config/production/config.json': unable to parse file: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}"), }, { name: "test JSON array", @@ -1206,11 +1321,11 @@ cluster: t.Run(testCaseCopy.name, func(t *testing.T) { t.Parallel() - argoCDServiceMock := argoCDServiceMock{mock: &mock.Mock{}} - argoCDServiceMock.mock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + argoCDServiceMock := mocks.Repos{} + argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError) - var gitGenerator = NewGitGenerator(argoCDServiceMock) + var gitGenerator = NewGitGenerator(&argoCDServiceMock) applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "set", @@ -1237,7 +1352,7 @@ cluster: assert.ElementsMatch(t, testCaseCopy.expected, got) } - argoCDServiceMock.mock.AssertExpectations(t) + argoCDServiceMock.AssertExpectations(t) }) } } diff --git a/applicationset/generators/list.go b/applicationset/generators/list.go index cff4c67f161dd..b3afabe6dac7d 100644 --- a/applicationset/generators/list.go +++ b/applicationset/generators/list.go @@ -5,6 +5,8 @@ import ( "fmt" "time" + "sigs.k8s.io/yaml" + argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) @@ -73,5 +75,16 @@ func (g *ListGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Appli } } + // Append elements from ElementsYaml to the response + if len(appSetGenerator.List.ElementsYaml) > 0 { + + var yamlElements []map[string]interface{} + err := yaml.Unmarshal([]byte(appSetGenerator.List.ElementsYaml), &yamlElements) + if err != nil { + return nil, fmt.Errorf("error unmarshling decoded ElementsYaml %v", err) + } + res = append(res, yamlElements...) + } + return res, nil } diff --git a/applicationset/generators/matrix.go b/applicationset/generators/matrix.go index eadd18b83d5f9..3edac086a4b3c 100644 --- a/applicationset/generators/matrix.go +++ b/applicationset/generators/matrix.go @@ -8,6 +8,8 @@ import ( "github.com/argoproj/argo-cd/v2/applicationset/utils" argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + + log "github.com/sirupsen/logrus" ) var _ Generator = (*MatrixGenerator)(nil) @@ -48,7 +50,7 @@ func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.App g0, err := m.getParams(appSetGenerator.Matrix.Generators[0], appSet, nil) if err != nil { - return nil, err + return nil, fmt.Errorf("error failed to get params for first generator in matrix generator: %w", err) } for _, a := range g0 { g1, err := m.getParams(appSetGenerator.Matrix.Generators[1], appSet, a) @@ -59,11 +61,11 @@ func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.App if appSet.Spec.GoTemplate { tmp := map[string]interface{}{} - if err := mergo.Merge(&tmp, a); err != nil { - return nil, fmt.Errorf("failed to merge params from the first generator in the matrix generator with temp map: %w", err) + if err := mergo.Merge(&tmp, b, mergo.WithOverride); err != nil { + return nil, fmt.Errorf("failed to merge params from the second generator in the matrix generator with temp map: %w", err) } - if err := mergo.Merge(&tmp, b); err != nil { - return nil, fmt.Errorf("failed to merge params from the first generator in the matrix generator with the second: %w", err) + if err := mergo.Merge(&tmp, a, mergo.WithOverride); err != nil { + return nil, fmt.Errorf("failed to merge params from the second generator in the matrix generator with the first: %w", err) } res = append(res, tmp) } else { @@ -80,27 +82,24 @@ func (m *MatrixGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.App } func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet, params map[string]interface{}) ([]map[string]interface{}, error) { - var matrix *argoprojiov1alpha1.MatrixGenerator - if appSetBaseGenerator.Matrix != nil { - // Since nested matrix generator is represented as a JSON object in the CRD, we unmarshall it back to a Go struct here. - nestedMatrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(appSetBaseGenerator.Matrix) - if err != nil { - return nil, fmt.Errorf("unable to unmarshall nested matrix generator: %v", err) - } - if nestedMatrix != nil { - matrix = nestedMatrix.ToMatrixGenerator() - } + matrixGen, err := getMatrixGenerator(appSetBaseGenerator) + if err != nil { + return nil, err } - - var mergeGenerator *argoprojiov1alpha1.MergeGenerator - if appSetBaseGenerator.Merge != nil { - // Since nested merge generator is represented as a JSON object in the CRD, we unmarshall it back to a Go struct here. - nestedMerge, err := argoprojiov1alpha1.ToNestedMergeGenerator(appSetBaseGenerator.Merge) - if err != nil { - return nil, fmt.Errorf("unable to unmarshall nested merge generator: %v", err) + if matrixGen != nil && !appSet.Spec.ApplyNestedSelectors { + foundSelector := dropDisabledNestedSelectors(matrixGen.Generators) + if foundSelector { + log.Warnf("AppSet '%v' defines selector on nested matrix generator's generator without enabling them via 'spec.applyNestedSelectors', ignoring nested selectors", appSet.Name) } - if nestedMerge != nil { - mergeGenerator = nestedMerge.ToMergeGenerator() + } + mergeGen, err := getMergeGenerator(appSetBaseGenerator) + if err != nil { + return nil, fmt.Errorf("error retrieving merge generator: %w", err) + } + if mergeGen != nil && !appSet.Spec.ApplyNestedSelectors { + foundSelector := dropDisabledNestedSelectors(mergeGen.Generators) + if foundSelector { + log.Warnf("AppSet '%v' defines selector on nested merge generator's generator without enabling them via 'spec.applyNestedSelectors', ignoring nested selectors", appSet.Name) } } @@ -112,8 +111,9 @@ func (m *MatrixGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Appli SCMProvider: appSetBaseGenerator.SCMProvider, ClusterDecisionResource: appSetBaseGenerator.ClusterDecisionResource, PullRequest: appSetBaseGenerator.PullRequest, - Matrix: matrix, - Merge: mergeGenerator, + Plugin: appSetBaseGenerator.Plugin, + Matrix: matrixGen, + Merge: mergeGen, Selector: appSetBaseGenerator.Selector, }, m.supportedGenerators, @@ -143,11 +143,18 @@ func (m *MatrixGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Ap var found bool for _, r := range appSetGenerator.Matrix.Generators { + matrixGen, _ := getMatrixGenerator(r) + mergeGen, _ := getMergeGenerator(r) base := &argoprojiov1alpha1.ApplicationSetGenerator{ - List: r.List, - Clusters: r.Clusters, - Git: r.Git, - PullRequest: r.PullRequest, + List: r.List, + Clusters: r.Clusters, + Git: r.Git, + PullRequest: r.PullRequest, + Plugin: r.Plugin, + SCMProvider: r.SCMProvider, + ClusterDecisionResource: r.ClusterDecisionResource, + Matrix: matrixGen, + Merge: mergeGen, } generators := GetRelevantGenerators(base, m.supportedGenerators) @@ -168,6 +175,17 @@ func (m *MatrixGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Ap } +func getMatrixGenerator(r argoprojiov1alpha1.ApplicationSetNestedGenerator) (*argoprojiov1alpha1.MatrixGenerator, error) { + if r.Matrix == nil { + return nil, nil + } + matrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(r.Matrix) + if err != nil { + return nil, err + } + return matrix.ToMatrixGenerator(), nil +} + func (m *MatrixGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate { return &appSetGenerator.Matrix.Template } diff --git a/applicationset/generators/matrix_test.go b/applicationset/generators/matrix_test.go index 1d79c452f6dce..21e88710ae618 100644 --- a/applicationset/generators/matrix_test.go +++ b/applicationset/generators/matrix_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -12,6 +13,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" + "github.com/argoproj/argo-cd/v2/applicationset/services/mocks" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -28,7 +31,7 @@ func TestMatrixGenerate(t *testing.T) { } listGenerator := &argoprojiov1alpha1.ListGenerator{ - Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "Cluster","url": "Url"}`)}}, + Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "Cluster","url": "Url", "templated": "test-{{path.basenameNormalized}}"}`)}}, } testCases := []struct { @@ -48,8 +51,8 @@ func TestMatrixGenerate(t *testing.T) { }, }, expected: []map[string]interface{}{ - {"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "cluster": "Cluster", "url": "Url"}, - {"path": "app2", "path.basename": "app2", "path.basenameNormalized": "app2", "cluster": "Cluster", "url": "Url"}, + {"path": "app1", "path.basename": "app1", "path.basenameNormalized": "app1", "cluster": "Cluster", "url": "Url", "templated": "test-app1"}, + {"path": "app2", "path.basename": "app2", "path.basenameNormalized": "app2", "cluster": "Cluster", "url": "Url", "templated": "test-app2"}, }, }, { @@ -268,6 +271,28 @@ func TestMatrixGenerateGoTemplate(t *testing.T) { {"a": "2", "b": "2"}, }, }, + { + name: "parameter override: first list elements take precedence", + baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{ + { + List: &argoprojiov1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{ + {Raw: []byte(`{"booleanFalse": false, "booleanTrue": true, "stringFalse": "false", "stringTrue": "true"}`)}, + }, + }, + }, + { + List: &argoprojiov1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{ + {Raw: []byte(`{"booleanFalse": true, "booleanTrue": false, "stringFalse": "true", "stringTrue": "false"}`)}, + }, + }, + }, + }, + expected: []map[string]interface{}{ + {"booleanFalse": false, "booleanTrue": true, "stringFalse": "false", "stringTrue": "true"}, + }, + }, { name: "returns error if there is less than two base generators", baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{ @@ -401,6 +426,10 @@ func TestMatrixGetRequeueAfter(t *testing.T) { pullRequestGenerator := &argoprojiov1alpha1.PullRequestGenerator{} + scmGenerator := &argoprojiov1alpha1.SCMProviderGenerator{} + + duckTypeGenerator := &argoprojiov1alpha1.DuckTypeGenerator{} + testCases := []struct { name string baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator @@ -458,6 +487,30 @@ func TestMatrixGetRequeueAfter(t *testing.T) { }, expected: time.Duration(30 * time.Minute), }, + { + name: "returns the default time for duck type generator", + baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{ + { + Git: gitGenerator, + }, + { + ClusterDecisionResource: duckTypeGenerator, + }, + }, + expected: time.Duration(3 * time.Minute), + }, + { + name: "returns the default time for scm generator", + baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{ + { + Git: gitGenerator, + }, + { + SCMProvider: scmGenerator, + }, + }, + expected: time.Duration(30 * time.Minute), + }, } for _, testCase := range testCases { @@ -468,18 +521,22 @@ func TestMatrixGetRequeueAfter(t *testing.T) { for _, g := range testCaseCopy.baseGenerators { gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{ - Git: g.Git, - List: g.List, - PullRequest: g.PullRequest, + Git: g.Git, + List: g.List, + PullRequest: g.PullRequest, + SCMProvider: g.SCMProvider, + ClusterDecisionResource: g.ClusterDecisionResource, } mock.On("GetRequeueAfter", &gitGeneratorSpec).Return(testCaseCopy.gitGetRequeueAfter, nil) } var matrixGenerator = NewMatrixGenerator( map[string]Generator{ - "Git": mock, - "List": &ListGenerator{}, - "PullRequest": &PullRequestGenerator{}, + "Git": mock, + "List": &ListGenerator{}, + "PullRequest": &PullRequestGenerator{}, + "SCMProvider": &SCMProviderGenerator{}, + "ClusterDecisionResource": &DuckTypeGenerator{}, }, ) @@ -835,6 +892,172 @@ func TestInterpolatedMatrixGenerateGoTemplate(t *testing.T) { } } +func TestMatrixGenerateListElementsYaml(t *testing.T) { + + gitGenerator := &argoprojiov1alpha1.GitGenerator{ + RepoURL: "RepoURL", + Revision: "Revision", + Files: []argoprojiov1alpha1.GitFileGeneratorItem{ + {Path: "config.yaml"}, + }, + } + + listGenerator := &argoprojiov1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{}, + ElementsYaml: "{{ .foo.bar | toJson }}", + } + + testCases := []struct { + name string + baseGenerators []argoprojiov1alpha1.ApplicationSetNestedGenerator + expectedErr error + expected []map[string]interface{} + }{ + { + name: "happy flow - generate params", + baseGenerators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{ + { + Git: gitGenerator, + }, + { + List: listGenerator, + }, + }, + expected: []map[string]interface{}{ + { + "chart": "a", + "version": "1", + "foo": map[string]interface{}{ + "bar": []interface{}{ + map[string]interface{}{ + "chart": "a", + "version": "1", + }, + map[string]interface{}{ + "chart": "b", + "version": "2", + }, + }, + }, + "path": map[string]interface{}{ + "basename": "dir", + "basenameNormalized": "dir", + "filename": "file_name.yaml", + "filenameNormalized": "file-name.yaml", + "path": "path/dir", + "segments": []string{ + "path", + "dir", + }, + }, + }, + { + "chart": "b", + "version": "2", + "foo": map[string]interface{}{ + "bar": []interface{}{ + map[string]interface{}{ + "chart": "a", + "version": "1", + }, + map[string]interface{}{ + "chart": "b", + "version": "2", + }, + }, + }, + "path": map[string]interface{}{ + "basename": "dir", + "basenameNormalized": "dir", + "filename": "file_name.yaml", + "filenameNormalized": "file-name.yaml", + "path": "path/dir", + "segments": []string{ + "path", + "dir", + }, + }, + }, + }, + }, + } + + for _, testCase := range testCases { + testCaseCopy := testCase // Since tests may run in parallel + + t.Run(testCaseCopy.name, func(t *testing.T) { + genMock := &generatorMock{} + appSet := &argoprojiov1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "set", + }, + Spec: argoprojiov1alpha1.ApplicationSetSpec{ + GoTemplate: true, + }, + } + + for _, g := range testCaseCopy.baseGenerators { + + gitGeneratorSpec := argoprojiov1alpha1.ApplicationSetGenerator{ + Git: g.Git, + List: g.List, + } + genMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), appSet).Return([]map[string]any{{ + "foo": map[string]interface{}{ + "bar": []interface{}{ + map[string]interface{}{ + "chart": "a", + "version": "1", + }, + map[string]interface{}{ + "chart": "b", + "version": "2", + }, + }, + }, + "path": map[string]interface{}{ + "basename": "dir", + "basenameNormalized": "dir", + "filename": "file_name.yaml", + "filenameNormalized": "file-name.yaml", + "path": "path/dir", + "segments": []string{ + "path", + "dir", + }, + }, + }}, nil) + genMock.On("GetTemplate", &gitGeneratorSpec). + Return(&argoprojiov1alpha1.ApplicationSetTemplate{}) + + } + + var matrixGenerator = NewMatrixGenerator( + map[string]Generator{ + "Git": genMock, + "List": &ListGenerator{}, + }, + ) + + got, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{ + Matrix: &argoprojiov1alpha1.MatrixGenerator{ + Generators: testCaseCopy.baseGenerators, + Template: argoprojiov1alpha1.ApplicationSetTemplate{}, + }, + }, appSet) + + if testCaseCopy.expectedErr != nil { + assert.ErrorIs(t, err, testCaseCopy.expectedErr) + } else { + assert.NoError(t, err) + assert.Equal(t, testCaseCopy.expected, got) + } + + }) + + } +} + type generatorMock struct { mock.Mock } @@ -857,3 +1080,72 @@ func (g *generatorMock) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Appl return args.Get(0).(time.Duration) } + +func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) { + // Given a matrix generator over a list generator and a git files generator, the nested git files generator should + // be treated as a files generator, and it should produce parameters. + + // This tests for a specific bug where a nested git files generator was being treated as a directory generator. This + // happened because, when the matrix generator was being processed, the nested git files generator was being + // interpolated by the deeplyReplace function. That function cannot differentiate between a nil slice and an empty + // slice. So it was replacing the `Directories` field with an empty slice, which the ApplicationSet controller + // interpreted as meaning this was a directory generator, not a files generator. + + // Now instead of checking for nil, we check whether the field is a non-empty slice. This test prevents a regression + // of that bug. + + listGeneratorMock := &generatorMock{} + listGeneratorMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), mock.AnythingOfType("*v1alpha1.ApplicationSet")).Return([]map[string]interface{}{ + {"some": "value"}, + }, nil) + listGeneratorMock.On("GetTemplate", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator")).Return(&argoprojiov1alpha1.ApplicationSetTemplate{}) + + gitGeneratorSpec := &argoprojiov1alpha1.GitGenerator{ + RepoURL: "https://git.example.com", + Files: []argoprojiov1alpha1.GitFileGeneratorItem{ + {Path: "some/path.json"}, + }, + } + + repoServiceMock := &mocks.Repos{} + 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) + + matrixGenerator := NewMatrixGenerator(map[string]Generator{ + "List": listGeneratorMock, + "Git": gitGenerator, + }) + + matrixGeneratorSpec := &argoprojiov1alpha1.MatrixGenerator{ + Generators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{ + { + List: &argoprojiov1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{ + { + Raw: []byte(`{"some": "value"}`), + }, + }, + }, + }, + { + Git: gitGeneratorSpec, + }, + }, + } + params, err := matrixGenerator.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{ + Matrix: matrixGeneratorSpec, + }, &argoprojiov1alpha1.ApplicationSet{}) + require.NoError(t, err) + assert.Equal(t, []map[string]interface{}{{ + "path": "some", + "path.basename": "some", + "path.basenameNormalized": "some", + "path.filename": "path.json", + "path.filenameNormalized": "path.json", + "path[0]": "some", + "some": "value", + "test": "content", + }}, params) +} diff --git a/applicationset/generators/merge.go b/applicationset/generators/merge.go index 69733c847e92d..ebda7180df70f 100644 --- a/applicationset/generators/merge.go +++ b/applicationset/generators/merge.go @@ -9,6 +9,8 @@ import ( "github.com/argoproj/argo-cd/v2/applicationset/utils" argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + + log "github.com/sirupsen/logrus" ) var _ Generator = (*MergeGenerator)(nil) @@ -36,10 +38,10 @@ func NewMergeGenerator(supportedGenerators map[string]Generator) Generator { // in slices ordered according to the order of the given generators. func (m *MergeGenerator) getParamSetsForAllGenerators(generators []argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([][]map[string]interface{}, error) { var paramSets [][]map[string]interface{} - for _, generator := range generators { + for i, generator := range generators { generatorParamSets, err := m.getParams(generator, appSet) if err != nil { - return nil, err + return nil, fmt.Errorf("error getting params from generator %d of %d: %w", i+1, len(generators), err) } // concatenate param lists produced by each generator paramSets = append(paramSets, generatorParamSets) @@ -59,18 +61,18 @@ func (m *MergeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Appl paramSetsFromGenerators, err := m.getParamSetsForAllGenerators(appSetGenerator.Merge.Generators, appSet) if err != nil { - return nil, err + return nil, fmt.Errorf("error getting param sets from generators: %w", err) } baseParamSetsByMergeKey, err := getParamSetsByMergeKey(appSetGenerator.Merge.MergeKeys, paramSetsFromGenerators[0]) if err != nil { - return nil, err + return nil, fmt.Errorf("error getting param sets by merge key: %w", err) } for _, paramSets := range paramSetsFromGenerators[1:] { paramSetsByMergeKey, err := getParamSetsByMergeKey(appSetGenerator.Merge.MergeKeys, paramSets) if err != nil { - return nil, err + return nil, fmt.Errorf("error getting param sets by merge key: %w", err) } for mergeKeyValue, baseParamSet := range baseParamSetsByMergeKey { @@ -78,13 +80,13 @@ func (m *MergeGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Appl if appSet.Spec.GoTemplate { if err := mergo.Merge(&baseParamSet, overrideParamSet, mergo.WithOverride); err != nil { - return nil, fmt.Errorf("failed to merge base param set with override param set: %w", err) + return nil, fmt.Errorf("error merging base param set with override param set: %w", err) } baseParamSetsByMergeKey[mergeKeyValue] = baseParamSet } else { overriddenParamSet, err := utils.CombineStringMapsAllowDuplicates(baseParamSet, overrideParamSet) if err != nil { - return nil, err + return nil, fmt.Errorf("error combining string maps: %w", err) } baseParamSetsByMergeKey[mergeKeyValue] = utils.ConvertToMapStringInterface(overriddenParamSet) } @@ -123,7 +125,7 @@ func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]interface } paramSetKeyJson, err := json.Marshal(paramSetKey) if err != nil { - return nil, err + return nil, fmt.Errorf("error marshalling param set key json: %w", err) } paramSetKeyString := string(paramSetKeyJson) if _, exists := paramSetsByMergeKey[paramSetKeyString]; exists { @@ -137,26 +139,24 @@ func getParamSetsByMergeKey(mergeKeys []string, paramSets []map[string]interface // getParams get the parameters generated by this generator. func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.ApplicationSetNestedGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) { - - var matrix *argoprojiov1alpha1.MatrixGenerator - if appSetBaseGenerator.Matrix != nil { - nestedMatrix, err := argoprojiov1alpha1.ToNestedMatrixGenerator(appSetBaseGenerator.Matrix) - if err != nil { - return nil, err - } - if nestedMatrix != nil { - matrix = nestedMatrix.ToMatrixGenerator() - } + matrixGen, err := getMatrixGenerator(appSetBaseGenerator) + if err != nil { + return nil, err } - - var mergeGenerator *argoprojiov1alpha1.MergeGenerator - if appSetBaseGenerator.Merge != nil { - nestedMerge, err := argoprojiov1alpha1.ToNestedMergeGenerator(appSetBaseGenerator.Merge) - if err != nil { - return nil, err + if matrixGen != nil && !appSet.Spec.ApplyNestedSelectors { + foundSelector := dropDisabledNestedSelectors(matrixGen.Generators) + if foundSelector { + log.Warnf("AppSet '%v' defines selector on nested matrix generator's generator without enabling them via 'spec.applyNestedSelectors', ignoring nested selector", appSet.Name) } - if nestedMerge != nil { - mergeGenerator = nestedMerge.ToMergeGenerator() + } + mergeGen, err := getMergeGenerator(appSetBaseGenerator) + if err != nil { + return nil, err + } + if mergeGen != nil && !appSet.Spec.ApplyNestedSelectors { + foundSelector := dropDisabledNestedSelectors(mergeGen.Generators) + if foundSelector { + log.Warnf("AppSet '%v' defines selector on nested merge generator's generator without enabling them via 'spec.applyNestedSelectors', ignoring nested selector", appSet.Name) } } @@ -168,8 +168,9 @@ func (m *MergeGenerator) getParams(appSetBaseGenerator argoprojiov1alpha1.Applic SCMProvider: appSetBaseGenerator.SCMProvider, ClusterDecisionResource: appSetBaseGenerator.ClusterDecisionResource, PullRequest: appSetBaseGenerator.PullRequest, - Matrix: matrix, - Merge: mergeGenerator, + Plugin: appSetBaseGenerator.Plugin, + Matrix: matrixGen, + Merge: mergeGen, Selector: appSetBaseGenerator.Selector, }, m.supportedGenerators, @@ -197,10 +198,18 @@ func (m *MergeGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.App var found bool for _, r := range appSetGenerator.Merge.Generators { + matrixGen, _ := getMatrixGenerator(r) + mergeGen, _ := getMergeGenerator(r) base := &argoprojiov1alpha1.ApplicationSetGenerator{ - List: r.List, - Clusters: r.Clusters, - Git: r.Git, + List: r.List, + Clusters: r.Clusters, + Git: r.Git, + PullRequest: r.PullRequest, + Plugin: r.Plugin, + SCMProvider: r.SCMProvider, + ClusterDecisionResource: r.ClusterDecisionResource, + Matrix: matrixGen, + Merge: mergeGen, } generators := GetRelevantGenerators(base, m.supportedGenerators) @@ -221,6 +230,17 @@ func (m *MergeGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.App } +func getMergeGenerator(r argoprojiov1alpha1.ApplicationSetNestedGenerator) (*argoprojiov1alpha1.MergeGenerator, error) { + if r.Merge == nil { + return nil, nil + } + merge, err := argoprojiov1alpha1.ToNestedMergeGenerator(r.Merge) + if err != nil { + return nil, fmt.Errorf("error converting to nested merge generator: %w", err) + } + return merge.ToMergeGenerator(), nil +} + // GetTemplate gets the Template field for the MergeGenerator. func (m *MergeGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate { return &appSetGenerator.Merge.Template diff --git a/applicationset/generators/plugin.go b/applicationset/generators/plugin.go new file mode 100644 index 0000000000000..e0acca0622cdc --- /dev/null +++ b/applicationset/generators/plugin.go @@ -0,0 +1,211 @@ +package generators + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + "github.com/jeremywohl/flatten" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/kubernetes" + "sigs.k8s.io/controller-runtime/pkg/client" + + argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/v2/util/settings" + + "github.com/argoproj/argo-cd/v2/applicationset/services/plugin" +) + +const ( + DefaultPluginRequeueAfterSeconds = 30 * time.Minute +) + +var _ Generator = (*PluginGenerator)(nil) + +type PluginGenerator struct { + client client.Client + ctx context.Context + clientset kubernetes.Interface + namespace string +} + +func NewPluginGenerator(client client.Client, ctx context.Context, clientset kubernetes.Interface, namespace string) Generator { + g := &PluginGenerator{ + client: client, + ctx: ctx, + clientset: clientset, + namespace: namespace, + } + return g +} + +func (g *PluginGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration { + // Return a requeue default of 30 minutes, if no default is specified. + + if appSetGenerator.Plugin.RequeueAfterSeconds != nil { + return time.Duration(*appSetGenerator.Plugin.RequeueAfterSeconds) * time.Second + } + + return DefaultPluginRequeueAfterSeconds +} + +func (g *PluginGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate { + return &appSetGenerator.Plugin.Template +} + +func (g *PluginGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) { + + if appSetGenerator == nil { + return nil, EmptyAppSetGeneratorError + } + + if appSetGenerator.Plugin == nil { + return nil, EmptyAppSetGeneratorError + } + + ctx := context.Background() + + providerConfig := appSetGenerator.Plugin + + pluginClient, err := g.getPluginFromGenerator(ctx, applicationSetInfo.Name, providerConfig) + if err != nil { + return nil, fmt.Errorf("error getting plugin from generator: %w", err) + } + + list, err := pluginClient.List(ctx, providerConfig.Input.Parameters) + if err != nil { + return nil, fmt.Errorf("error listing params: %w", err) + } + + res, err := g.generateParams(appSetGenerator, applicationSetInfo, list.Output.Parameters, appSetGenerator.Plugin.Input.Parameters, applicationSetInfo.Spec.GoTemplate) + if err != nil { + return nil, fmt.Errorf("error generating params: %w", err) + } + + return res, nil +} + +func (g *PluginGenerator) getPluginFromGenerator(ctx context.Context, appSetName string, generatorConfig *argoprojiov1alpha1.PluginGenerator) (*plugin.Service, error) { + cm, err := g.getConfigMap(ctx, generatorConfig.ConfigMapRef.Name) + if err != nil { + return nil, fmt.Errorf("error fetching ConfigMap: %w", err) + } + token, err := g.getToken(ctx, cm["token"]) + if err != nil { + return nil, fmt.Errorf("error fetching Secret token: %v", err) + } + + var requestTimeout int + requestTimeoutStr, ok := cm["requestTimeout"] + if ok { + requestTimeout, err = strconv.Atoi(requestTimeoutStr) + if err != nil { + return nil, fmt.Errorf("error set requestTimeout : %w", err) + } + } + + pluginClient, err := plugin.NewPluginService(ctx, appSetName, cm["baseUrl"], token, requestTimeout) + if err != nil { + return nil, fmt.Errorf("error initializing plugin client: %w", err) + } + return pluginClient, nil +} + +func (g *PluginGenerator) generateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet, objectsFound []map[string]interface{}, pluginParams argoprojiov1alpha1.PluginParameters, useGoTemplate bool) ([]map[string]interface{}, error) { + res := []map[string]interface{}{} + + for _, objectFound := range objectsFound { + + params := map[string]interface{}{} + + if useGoTemplate { + for k, v := range objectFound { + params[k] = v + } + } else { + flat, err := flatten.Flatten(objectFound, "", flatten.DotStyle) + if err != nil { + return nil, err + } + for k, v := range flat { + params[k] = fmt.Sprintf("%v", v) + } + } + + params["generator"] = map[string]interface{}{ + "input": map[string]argoprojiov1alpha1.PluginParameters{ + "parameters": pluginParams, + }, + } + + err := appendTemplatedValues(appSetGenerator.Plugin.Values, params, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions) + if err != nil { + return nil, err + } + + res = append(res, params) + } + + return res, nil +} + +func (g *PluginGenerator) getToken(ctx context.Context, tokenRef string) (string, error) { + + if tokenRef == "" || !strings.HasPrefix(tokenRef, "$") { + return "", fmt.Errorf("token is empty, or does not reference a secret key starting with '$': %v", tokenRef) + } + + secretName, tokenKey := plugin.ParseSecretKey(tokenRef) + + secret := &corev1.Secret{} + err := g.client.Get( + ctx, + client.ObjectKey{ + Name: secretName, + Namespace: g.namespace, + }, + secret) + + if err != nil { + return "", fmt.Errorf("error fetching secret %s/%s: %v", g.namespace, secretName, err) + } + + secretValues := make(map[string]string, len(secret.Data)) + + for k, v := range secret.Data { + secretValues[k] = string(v) + } + + token := settings.ReplaceStringSecret(tokenKey, secretValues) + + return token, err +} + +func (g *PluginGenerator) getConfigMap(ctx context.Context, configMapRef string) (map[string]string, error) { + cm := &corev1.ConfigMap{} + err := g.client.Get( + ctx, + client.ObjectKey{ + Name: configMapRef, + Namespace: g.namespace, + }, + cm) + + if err != nil { + return nil, err + } + + baseUrl, ok := cm.Data["baseUrl"] + if !ok || baseUrl == "" { + return nil, fmt.Errorf("baseUrl not found in ConfigMap") + } + + token, ok := cm.Data["token"] + if !ok || token == "" { + return nil, fmt.Errorf("token not found in ConfigMap") + } + + return cm.Data, nil +} diff --git a/applicationset/generators/plugin_test.go b/applicationset/generators/plugin_test.go new file mode 100644 index 0000000000000..9611a2cbf14c1 --- /dev/null +++ b/applicationset/generators/plugin_test.go @@ -0,0 +1,705 @@ +package generators + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + kubefake "k8s.io/client-go/kubernetes/fake" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/argoproj/argo-cd/v2/applicationset/services/plugin" + argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" +) + +func TestPluginGenerateParams(t *testing.T) { + testCases := []struct { + name string + configmap *v1.ConfigMap + secret *v1.Secret + inputParameters map[string]apiextensionsv1.JSON + values map[string]string + gotemplate bool + expected []map[string]interface{} + content []byte + expectedError error + }{ + { + name: "simple case", + configmap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "first-plugin-cm", + Namespace: "default", + }, + Data: map[string]string{ + "baseUrl": "http://127.0.0.1", + "token": "$plugin.token", + }, + }, + secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "plugin.token": []byte("my-secret"), + }, + }, + inputParameters: map[string]apiextensionsv1.JSON{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + gotemplate: false, + content: []byte(`{"output": { + "parameters": [{ + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123 + }] + }}`), + expected: []map[string]interface{}{ + { + "key1": "val1", + "key2.key2_1": "val2_1", + "key2.key2_2.key2_2_1": "val2_2_1", + "key3": "123", + "generator": map[string]interface{}{ + "input": argoprojiov1alpha1.PluginInput{ + Parameters: argoprojiov1alpha1.PluginParameters{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + }, + }, + }, + }, + expectedError: nil, + }, + { + name: "simple case with values", + configmap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "first-plugin-cm", + Namespace: "default", + }, + Data: map[string]string{ + "baseUrl": "http://127.0.0.1", + "token": "$plugin.token", + }, + }, + secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "plugin.token": []byte("my-secret"), + }, + }, + inputParameters: map[string]apiextensionsv1.JSON{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + values: map[string]string{ + "valuekey1": "valuevalue1", + "valuekey2": "templated-{{key1}}", + }, + gotemplate: false, + content: []byte(`{"output": { + "parameters": [{ + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123 + }] + }}`), + expected: []map[string]interface{}{ + { + "key1": "val1", + "key2.key2_1": "val2_1", + "key2.key2_2.key2_2_1": "val2_2_1", + "key3": "123", + "values.valuekey1": "valuevalue1", + "values.valuekey2": "templated-val1", + "generator": map[string]interface{}{ + "input": argoprojiov1alpha1.PluginInput{ + Parameters: argoprojiov1alpha1.PluginParameters{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + }, + }, + }, + }, + expectedError: nil, + }, + { + name: "simple case with gotemplate", + configmap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "first-plugin-cm", + Namespace: "default", + }, + Data: map[string]string{ + "baseUrl": "http://127.0.0.1", + "token": "$plugin.token", + }, + }, + secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "plugin.token": []byte("my-secret"), + }, + }, + inputParameters: map[string]apiextensionsv1.JSON{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + gotemplate: true, + content: []byte(`{"output": { + "parameters": [{ + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123 + }] + }}`), + expected: []map[string]interface{}{ + { + "key1": "val1", + "key2": map[string]interface{}{ + "key2_1": "val2_1", + "key2_2": map[string]interface{}{ + "key2_2_1": "val2_2_1", + }, + }, + "key3": float64(123), + "generator": map[string]interface{}{ + "input": argoprojiov1alpha1.PluginInput{ + Parameters: argoprojiov1alpha1.PluginParameters{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + }, + }, + }, + }, + expectedError: nil, + }, + { + name: "simple case with appended params", + configmap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "first-plugin-cm", + Namespace: "default", + }, + Data: map[string]string{ + "baseUrl": "http://127.0.0.1", + "token": "$plugin.token", + }, + }, + secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "plugin.token": []byte("my-secret"), + }, + }, + inputParameters: map[string]apiextensionsv1.JSON{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + gotemplate: false, + content: []byte(`{"output": {"parameters": [{ + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123, + "pkey2": "valplugin" + }]}}`), + expected: []map[string]interface{}{ + { + "key1": "val1", + "key2.key2_1": "val2_1", + "key2.key2_2.key2_2_1": "val2_2_1", + "key3": "123", + "pkey2": "valplugin", + "generator": map[string]interface{}{ + "input": argoprojiov1alpha1.PluginInput{ + Parameters: argoprojiov1alpha1.PluginParameters{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + }, + }, + }, + }, + expectedError: nil, + }, + { + name: "no params", + configmap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "first-plugin-cm", + Namespace: "default", + }, + Data: map[string]string{ + "baseUrl": "http://127.0.0.1", + "token": "$plugin.token", + }, + }, + secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "plugin.token": []byte("my-secret"), + }, + }, + inputParameters: argoprojiov1alpha1.PluginParameters{}, + gotemplate: false, + content: []byte(`{"output": { + "parameters": [{ + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123 + }] + }}`), + expected: []map[string]interface{}{ + { + "key1": "val1", + "key2.key2_1": "val2_1", + "key2.key2_2.key2_2_1": "val2_2_1", + "key3": "123", + "generator": map[string]interface{}{ + "input": map[string]map[string]interface{}{ + "parameters": {}, + }, + }, + }, + }, + expectedError: nil, + }, + { + name: "empty return", + configmap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "first-plugin-cm", + Namespace: "default", + }, + Data: map[string]string{ + "baseUrl": "http://127.0.0.1", + "token": "$plugin.token", + }, + }, + secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "plugin.token": []byte("my-secret"), + }, + }, + inputParameters: map[string]apiextensionsv1.JSON{}, + gotemplate: false, + content: []byte(`{"input": {"parameters": []}}`), + expected: []map[string]interface{}{}, + expectedError: nil, + }, + { + name: "wrong return", + configmap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "first-plugin-cm", + Namespace: "default", + }, + Data: map[string]string{ + "baseUrl": "http://127.0.0.1", + "token": "$plugin.token", + }, + }, + secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "plugin.token": []byte("my-secret"), + }, + }, + inputParameters: map[string]apiextensionsv1.JSON{}, + gotemplate: false, + content: []byte(`wrong body ...`), + expected: []map[string]interface{}{}, + expectedError: fmt.Errorf("error listing params: error get api 'set': invalid character 'w' looking for beginning of value: wrong body ..."), + }, + { + name: "external secret", + configmap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "first-plugin-cm", + Namespace: "default", + }, + Data: map[string]string{ + "baseUrl": "http://127.0.0.1", + "token": "$plugin-secret:plugin.token", + }, + }, + secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "plugin-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "plugin.token": []byte("my-secret"), + }, + }, + inputParameters: map[string]apiextensionsv1.JSON{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + gotemplate: false, + content: []byte(`{"output": {"parameters": [{ + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123, + "pkey2": "valplugin" + }]}}`), + expected: []map[string]interface{}{ + { + "key1": "val1", + "key2.key2_1": "val2_1", + "key2.key2_2.key2_2_1": "val2_2_1", + "key3": "123", + "pkey2": "valplugin", + "generator": map[string]interface{}{ + "input": argoprojiov1alpha1.PluginInput{ + Parameters: argoprojiov1alpha1.PluginParameters{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + }, + }, + }, + }, + expectedError: nil, + }, + { + name: "no secret", + configmap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "first-plugin-cm", + Namespace: "default", + }, + Data: map[string]string{ + "baseUrl": "http://127.0.0.1", + "token": "$plugin.token", + }, + }, + secret: &v1.Secret{}, + inputParameters: map[string]apiextensionsv1.JSON{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + gotemplate: false, + content: []byte(`{"output": { + "parameters": [{ + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123 + }] + }}`), + expected: []map[string]interface{}{ + { + "key1": "val1", + "key2.key2_1": "val2_1", + "key2.key2_2.key2_2_1": "val2_2_1", + "key3": "123", + "generator": map[string]interface{}{ + "input": argoprojiov1alpha1.PluginInput{ + Parameters: argoprojiov1alpha1.PluginParameters{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + }, + }, + }, + }, + expectedError: fmt.Errorf("error getting plugin from generator: error fetching Secret token: error fetching secret default/argocd-secret: secrets \"argocd-secret\" not found"), + }, + { + name: "no configmap", + configmap: &v1.ConfigMap{}, + secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "plugin.token": []byte("my-secret"), + }, + }, + inputParameters: map[string]apiextensionsv1.JSON{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + gotemplate: false, + content: []byte(`{"output": { + "parameters": [{ + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123 + }] + }}`), + expected: []map[string]interface{}{ + { + "key1": "val1", + "key2.key2_1": "val2_1", + "key2.key2_2.key2_2_1": "val2_2_1", + "key3": "123", + "generator": map[string]interface{}{ + "input": argoprojiov1alpha1.PluginInput{ + Parameters: argoprojiov1alpha1.PluginParameters{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + }, + }, + }, + }, + expectedError: fmt.Errorf("error getting plugin from generator: error fetching ConfigMap: configmaps \"\" not found"), + }, + { + name: "no baseUrl", + configmap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "first-plugin-cm", + Namespace: "default", + }, + Data: map[string]string{ + "token": "$plugin.token", + }, + }, + secret: &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "plugin.token": []byte("my-secret"), + }, + }, + inputParameters: map[string]apiextensionsv1.JSON{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + gotemplate: false, + content: []byte(`{"output": { + "parameters": [{ + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123 + }] + }}`), + expected: []map[string]interface{}{ + { + "key1": "val1", + "key2.key2_1": "val2_1", + "key2.key2_2.key2_2_1": "val2_2_1", + "key3": "123", + "generator": map[string]interface{}{ + "input": argoprojiov1alpha1.PluginInput{ + Parameters: argoprojiov1alpha1.PluginParameters{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + }, + }, + }, + }, + expectedError: fmt.Errorf("error getting plugin from generator: error fetching ConfigMap: baseUrl not found in ConfigMap"), + }, + { + name: "no token", + configmap: &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "first-plugin-cm", + Namespace: "default", + }, + Data: map[string]string{ + "baseUrl": "http://127.0.0.1", + }, + }, + secret: &v1.Secret{}, + inputParameters: map[string]apiextensionsv1.JSON{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + gotemplate: false, + content: []byte(`{"output": { + "parameters": [{ + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123 + }] + }}`), + expected: []map[string]interface{}{ + { + "key1": "val1", + "key2.key2_1": "val2_1", + "key2.key2_2.key2_2_1": "val2_2_1", + "key3": "123", + "generator": map[string]interface{}{ + "input": argoprojiov1alpha1.PluginInput{ + Parameters: argoprojiov1alpha1.PluginParameters{ + "pkey1": {Raw: []byte(`"val1"`)}, + "pkey2": {Raw: []byte(`"val2"`)}, + }, + }, + }, + }, + }, + expectedError: fmt.Errorf("error getting plugin from generator: error fetching ConfigMap: token not found in ConfigMap"), + }, + } + + ctx := context.Background() + + for _, testCase := range testCases { + + t.Run(testCase.name, func(t *testing.T) { + + generatorConfig := argoprojiov1alpha1.ApplicationSetGenerator{ + Plugin: &argoprojiov1alpha1.PluginGenerator{ + ConfigMapRef: argoprojiov1alpha1.PluginConfigMapRef{Name: testCase.configmap.Name}, + Input: argoprojiov1alpha1.PluginInput{ + Parameters: testCase.inputParameters, + }, + Values: testCase.values, + }, + } + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + authHeader := r.Header.Get("Authorization") + _, tokenKey := plugin.ParseSecretKey(testCase.configmap.Data["token"]) + expectedToken := testCase.secret.Data[strings.Replace(tokenKey, "$", "", -1)] + if authHeader != "Bearer "+string(expectedToken) { + w.WriteHeader(http.StatusUnauthorized) + return + } + + w.Header().Set("Content-Type", "application/json") + _, err := w.Write(testCase.content) + if err != nil { + assert.NoError(t, fmt.Errorf("Error Write %v", err)) + } + }) + + fakeServer := httptest.NewServer(handler) + + defer fakeServer.Close() + + if _, ok := testCase.configmap.Data["baseUrl"]; ok { + testCase.configmap.Data["baseUrl"] = fakeServer.URL + } + + fakeClient := kubefake.NewSimpleClientset(append([]runtime.Object{}, testCase.configmap, testCase.secret)...) + + fakeClientWithCache := fake.NewClientBuilder().WithObjects([]client.Object{testCase.configmap, testCase.secret}...).Build() + + var pluginGenerator = NewPluginGenerator(fakeClientWithCache, ctx, fakeClient, "default") + + applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "set", + }, + Spec: argoprojiov1alpha1.ApplicationSetSpec{ + GoTemplate: testCase.gotemplate, + }, + } + + got, err := pluginGenerator.GenerateParams(&generatorConfig, &applicationSetInfo) + + if err != nil { + fmt.Println(err) + } + + if testCase.expectedError != nil { + assert.EqualError(t, err, testCase.expectedError.Error()) + } else { + assert.NoError(t, err) + expectedJson, err := json.Marshal(testCase.expected) + require.NoError(t, err) + gotJson, err := json.Marshal(got) + require.NoError(t, err) + assert.Equal(t, string(expectedJson), string(gotJson)) + } + }) + } +} diff --git a/applicationset/generators/pull_request.go b/applicationset/generators/pull_request.go index db6c80c6c0f5c..c1dfd5ed978e9 100644 --- a/applicationset/generators/pull_request.go +++ b/applicationset/generators/pull_request.go @@ -11,7 +11,6 @@ import ( "github.com/gosimple/slug" - "github.com/argoproj/argo-cd/v2/applicationset/services/pull_request" pullrequest "github.com/argoproj/argo-cd/v2/applicationset/services/pull_request" argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) @@ -26,12 +25,18 @@ type PullRequestGenerator struct { client client.Client selectServiceProviderFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) auth SCMAuthProviders + scmRootCAPath string + allowedSCMProviders []string + enableSCMProviders bool } -func NewPullRequestGenerator(client client.Client, auth SCMAuthProviders) Generator { +func NewPullRequestGenerator(client client.Client, auth SCMAuthProviders, scmRootCAPath string, allowedScmProviders []string, enableSCMProviders bool) Generator { g := &PullRequestGenerator{ - client: client, - auth: auth, + client: client, + auth: auth, + scmRootCAPath: scmRootCAPath, + allowedSCMProviders: allowedScmProviders, + enableSCMProviders: enableSCMProviders, } g.selectServiceProviderFunc = g.selectServiceProvider return g @@ -63,10 +68,10 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha ctx := context.Background() svc, err := g.selectServiceProviderFunc(ctx, appSetGenerator.PullRequest, applicationSetInfo) if err != nil { - return nil, fmt.Errorf("failed to select pull request service provider: %v", err) + return nil, fmt.Errorf("failed to select pull request service provider: %w", err) } - pulls, err := pull_request.ListPullRequests(ctx, svc, appSetGenerator.PullRequest.Filters) + pulls, err := pullrequest.ListPullRequests(ctx, svc, appSetGenerator.PullRequest.Filters) if err != nil { return nil, fmt.Errorf("error listing repos: %v", err) } @@ -84,18 +89,27 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha } var shortSHALength int + var shortSHALength7 int for _, pull := range pulls { shortSHALength = 8 if len(pull.HeadSHA) < 8 { shortSHALength = len(pull.HeadSHA) } + shortSHALength7 = 7 + if len(pull.HeadSHA) < 7 { + shortSHALength7 = len(pull.HeadSHA) + } + paramMap := map[string]interface{}{ - "number": strconv.Itoa(pull.Number), - "branch": pull.Branch, - "branch_slug": slug.Make(pull.Branch), - "head_sha": pull.HeadSHA, - "head_short_sha": pull.HeadSHA[:shortSHALength], + "number": strconv.Itoa(pull.Number), + "branch": pull.Branch, + "branch_slug": slug.Make(pull.Branch), + "target_branch": pull.TargetBranch, + "target_branch_slug": slug.Make(pull.TargetBranch), + "head_sha": pull.HeadSHA, + "head_short_sha": pull.HeadSHA[:shortSHALength], + "head_short_sha_7": pull.HeadSHA[:shortSHALength7], } // PR lables will only be supported for Go Template appsets, since fasttemplate will be deprecated. @@ -109,6 +123,13 @@ func (g *PullRequestGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha // selectServiceProvider selects the provider to get pull requests from the configuration func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, generatorConfig *argoprojiov1alpha1.PullRequestGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) { + if !g.enableSCMProviders { + return nil, ErrSCMProvidersDisabled + } + if err := ScmProviderAllowed(applicationSetInfo, generatorConfig, g.allowedSCMProviders); err != nil { + return nil, fmt.Errorf("scm provider not allowed: %w", err) + } + if generatorConfig.Github != nil { return g.github(ctx, generatorConfig.Github, applicationSetInfo) } @@ -118,7 +139,7 @@ func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, genera if err != nil { return nil, fmt.Errorf("error fetching Secret token: %v", err) } - return pullrequest.NewGitLabService(ctx, token, providerConfig.API, providerConfig.Project, providerConfig.Labels, providerConfig.PullRequestState) + return pullrequest.NewGitLabService(ctx, token, providerConfig.API, providerConfig.Project, providerConfig.Labels, providerConfig.PullRequestState, g.scmRootCAPath, providerConfig.Insecure) } if generatorConfig.Gitea != nil { providerConfig := generatorConfig.Gitea @@ -140,6 +161,32 @@ func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, genera return pullrequest.NewBitbucketServiceNoAuth(ctx, providerConfig.API, providerConfig.Project, providerConfig.Repo) } } + if generatorConfig.Bitbucket != nil { + providerConfig := generatorConfig.Bitbucket + if providerConfig.BearerToken != nil { + appToken, err := g.getSecretRef(ctx, providerConfig.BearerToken.TokenRef, applicationSetInfo.Namespace) + if err != nil { + return nil, fmt.Errorf("error fetching Secret Bearer token: %v", err) + } + return pullrequest.NewBitbucketCloudServiceBearerToken(providerConfig.API, appToken, providerConfig.Owner, providerConfig.Repo) + } else if providerConfig.BasicAuth != nil { + password, err := g.getSecretRef(ctx, providerConfig.BasicAuth.PasswordRef, applicationSetInfo.Namespace) + if err != nil { + return nil, fmt.Errorf("error fetching Secret token: %v", err) + } + return pullrequest.NewBitbucketCloudServiceBasicAuth(providerConfig.API, providerConfig.BasicAuth.Username, password, providerConfig.Owner, providerConfig.Repo) + } else { + return pullrequest.NewBitbucketCloudServiceNoAuth(providerConfig.API, providerConfig.Owner, providerConfig.Repo) + } + } + if generatorConfig.AzureDevOps != nil { + providerConfig := generatorConfig.AzureDevOps + token, err := g.getSecretRef(ctx, providerConfig.TokenRef, applicationSetInfo.Namespace) + if err != nil { + return nil, fmt.Errorf("error fetching Secret token: %v", err) + } + return pullrequest.NewAzureDevOpsService(ctx, token, providerConfig.API, providerConfig.Organization, providerConfig.Project, providerConfig.Repo, providerConfig.Labels) + } return nil, fmt.Errorf("no Pull Request provider implementation configured") } diff --git a/applicationset/generators/pull_request_test.go b/applicationset/generators/pull_request_test.go index caad198670302..9f4d3d0a9b693 100644 --- a/applicationset/generators/pull_request_test.go +++ b/applicationset/generators/pull_request_test.go @@ -27,10 +27,11 @@ func TestPullRequestGithubGenerateParams(t *testing.T) { return pullrequest.NewFakeService( ctx, []*pullrequest.PullRequest{ - &pullrequest.PullRequest{ - Number: 1, - Branch: "branch1", - HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958", + { + Number: 1, + Branch: "branch1", + TargetBranch: "master", + HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958", }, }, nil, @@ -38,11 +39,14 @@ func TestPullRequestGithubGenerateParams(t *testing.T) { }, expected: []map[string]interface{}{ { - "number": "1", - "branch": "branch1", - "branch_slug": "branch1", - "head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958", - "head_short_sha": "089d92cb", + "number": "1", + "branch": "branch1", + "branch_slug": "branch1", + "target_branch": "master", + "target_branch_slug": "master", + "head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958", + "head_short_sha": "089d92cb", + "head_short_sha_7": "089d92c", }, }, expectedErr: nil, @@ -52,10 +56,11 @@ func TestPullRequestGithubGenerateParams(t *testing.T) { return pullrequest.NewFakeService( ctx, []*pullrequest.PullRequest{ - &pullrequest.PullRequest{ - Number: 2, - Branch: "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", - HeadSHA: "9b34ff5bd418e57d58891eb0aa0728043ca1e8be", + { + Number: 2, + Branch: "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", + TargetBranch: "feat/anotherreally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", + HeadSHA: "9b34ff5bd418e57d58891eb0aa0728043ca1e8be", }, }, nil, @@ -63,11 +68,14 @@ func TestPullRequestGithubGenerateParams(t *testing.T) { }, expected: []map[string]interface{}{ { - "number": "2", - "branch": "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", - "branch_slug": "feat-areally-long-pull-request-name-to-test-argo", - "head_sha": "9b34ff5bd418e57d58891eb0aa0728043ca1e8be", - "head_short_sha": "9b34ff5b", + "number": "2", + "branch": "feat/areally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", + "branch_slug": "feat-areally-long-pull-request-name-to-test-argo", + "target_branch": "feat/anotherreally+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", + "target_branch_slug": "feat-anotherreally-long-pull-request-name-to-test", + "head_sha": "9b34ff5bd418e57d58891eb0aa0728043ca1e8be", + "head_short_sha": "9b34ff5b", + "head_short_sha_7": "9b34ff5", }, }, expectedErr: nil, @@ -77,10 +85,11 @@ func TestPullRequestGithubGenerateParams(t *testing.T) { return pullrequest.NewFakeService( ctx, []*pullrequest.PullRequest{ - &pullrequest.PullRequest{ - Number: 1, - Branch: "a-very-short-sha", - HeadSHA: "abcd", + { + Number: 1, + Branch: "a-very-short-sha", + TargetBranch: "master", + HeadSHA: "abcd", }, }, nil, @@ -88,11 +97,14 @@ func TestPullRequestGithubGenerateParams(t *testing.T) { }, expected: []map[string]interface{}{ { - "number": "1", - "branch": "a-very-short-sha", - "branch_slug": "a-very-short-sha", - "head_sha": "abcd", - "head_short_sha": "abcd", + "number": "1", + "branch": "a-very-short-sha", + "branch_slug": "a-very-short-sha", + "target_branch": "master", + "target_branch_slug": "master", + "head_sha": "abcd", + "head_short_sha": "abcd", + "head_short_sha_7": "abcd", }, }, expectedErr: nil, @@ -113,11 +125,12 @@ func TestPullRequestGithubGenerateParams(t *testing.T) { return pullrequest.NewFakeService( ctx, []*pullrequest.PullRequest{ - &pullrequest.PullRequest{ - Number: 1, - Branch: "branch1", - HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958", - Labels: []string{"preview"}, + { + Number: 1, + Branch: "branch1", + TargetBranch: "master", + HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958", + Labels: []string{"preview"}, }, }, nil, @@ -125,12 +138,15 @@ func TestPullRequestGithubGenerateParams(t *testing.T) { }, expected: []map[string]interface{}{ { - "number": "1", - "branch": "branch1", - "branch_slug": "branch1", - "head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958", - "head_short_sha": "089d92cb", - "labels": []string{"preview"}, + "number": "1", + "branch": "branch1", + "branch_slug": "branch1", + "target_branch": "master", + "target_branch_slug": "master", + "head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958", + "head_short_sha": "089d92cb", + "head_short_sha_7": "089d92c", + "labels": []string{"preview"}, }, }, expectedErr: nil, @@ -146,11 +162,12 @@ func TestPullRequestGithubGenerateParams(t *testing.T) { return pullrequest.NewFakeService( ctx, []*pullrequest.PullRequest{ - &pullrequest.PullRequest{ - Number: 1, - Branch: "branch1", - HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958", - Labels: []string{"preview"}, + { + Number: 1, + Branch: "branch1", + TargetBranch: "master", + HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958", + Labels: []string{"preview"}, }, }, nil, @@ -158,11 +175,14 @@ func TestPullRequestGithubGenerateParams(t *testing.T) { }, expected: []map[string]interface{}{ { - "number": "1", - "branch": "branch1", - "branch_slug": "branch1", - "head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958", - "head_short_sha": "089d92cb", + "number": "1", + "branch": "branch1", + "branch_slug": "branch1", + "target_branch": "master", + "target_branch_slug": "master", + "head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958", + "head_short_sha": "089d92cb", + "head_short_sha_7": "089d92c", }, }, expectedErr: nil, @@ -253,3 +273,102 @@ func TestPullRequestGetSecretRef(t *testing.T) { }) } } + +func TestAllowedSCMProviderPullRequest(t *testing.T) { + cases := []struct { + name string + providerConfig *argoprojiov1alpha1.PullRequestGenerator + expectedError error + }{ + { + name: "Error Github", + providerConfig: &argoprojiov1alpha1.PullRequestGenerator{ + Github: &argoprojiov1alpha1.PullRequestGeneratorGithub{ + API: "https://myservice.mynamespace.svc.cluster.local", + }, + }, + expectedError: &ErrDisallowedSCMProvider{}, + }, + { + name: "Error Gitlab", + providerConfig: &argoprojiov1alpha1.PullRequestGenerator{ + GitLab: &argoprojiov1alpha1.PullRequestGeneratorGitLab{ + API: "https://myservice.mynamespace.svc.cluster.local", + }, + }, + expectedError: &ErrDisallowedSCMProvider{}, + }, + { + name: "Error Gitea", + providerConfig: &argoprojiov1alpha1.PullRequestGenerator{ + Gitea: &argoprojiov1alpha1.PullRequestGeneratorGitea{ + API: "https://myservice.mynamespace.svc.cluster.local", + }, + }, + expectedError: &ErrDisallowedSCMProvider{}, + }, + { + name: "Error Bitbucket", + providerConfig: &argoprojiov1alpha1.PullRequestGenerator{ + BitbucketServer: &argoprojiov1alpha1.PullRequestGeneratorBitbucketServer{ + API: "https://myservice.mynamespace.svc.cluster.local", + }, + }, + expectedError: &ErrDisallowedSCMProvider{}, + }, + } + + for _, testCase := range cases { + testCaseCopy := testCase + + t.Run(testCaseCopy.name, func(t *testing.T) { + t.Parallel() + + pullRequestGenerator := NewPullRequestGenerator(nil, SCMAuthProviders{}, "", []string{ + "github.myorg.com", + "gitlab.myorg.com", + "gitea.myorg.com", + "bitbucket.myorg.com", + "azuredevops.myorg.com", + }, true) + + applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "set", + }, + Spec: argoprojiov1alpha1.ApplicationSetSpec{ + Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{ + PullRequest: testCaseCopy.providerConfig, + }}, + }, + } + + _, err := pullRequestGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo) + + assert.Error(t, err, "Must return an error") + assert.ErrorAs(t, err, testCaseCopy.expectedError) + }) + } +} + +func TestSCMProviderDisabled_PRGenerator(t *testing.T) { + generator := NewPullRequestGenerator(nil, SCMAuthProviders{}, "", []string{}, false) + + applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "set", + }, + Spec: argoprojiov1alpha1.ApplicationSetSpec{ + Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{ + PullRequest: &argoprojiov1alpha1.PullRequestGenerator{ + Github: &argoprojiov1alpha1.PullRequestGeneratorGithub{ + API: "https://myservice.mynamespace.svc.cluster.local", + }, + }, + }}, + }, + } + + _, err := generator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo) + assert.ErrorIs(t, err, ErrSCMProvidersDisabled) +} diff --git a/applicationset/generators/scm_provider.go b/applicationset/generators/scm_provider.go index 352b60d26d398..42b7789be67f0 100644 --- a/applicationset/generators/scm_provider.go +++ b/applicationset/generators/scm_provider.go @@ -2,6 +2,7 @@ package generators import ( "context" + "errors" "fmt" "strings" "time" @@ -9,9 +10,12 @@ import ( corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" + log "github.com/sirupsen/logrus" + "github.com/argoproj/argo-cd/v2/applicationset/services/github_app_auth" "github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider" "github.com/argoproj/argo-cd/v2/applicationset/utils" + "github.com/argoproj/argo-cd/v2/common" argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) @@ -26,22 +30,28 @@ type SCMProviderGenerator struct { // Testing hooks. overrideProvider scm_provider.SCMProviderService SCMAuthProviders + scmRootCAPath string + allowedSCMProviders []string + enableSCMProviders bool } type SCMAuthProviders struct { GitHubApps github_app_auth.Credentials } -func NewSCMProviderGenerator(client client.Client, providers SCMAuthProviders) Generator { +func NewSCMProviderGenerator(client client.Client, providers SCMAuthProviders, scmRootCAPath string, allowedSCMProviders []string, enableSCMProviders bool) Generator { return &SCMProviderGenerator{ - client: client, - SCMAuthProviders: providers, + client: client, + SCMAuthProviders: providers, + scmRootCAPath: scmRootCAPath, + allowedSCMProviders: allowedSCMProviders, + enableSCMProviders: enableSCMProviders, } } // Testing generator func NewTestSCMProviderGenerator(overrideProvider scm_provider.SCMProviderService) Generator { - return &SCMProviderGenerator{overrideProvider: overrideProvider} + return &SCMProviderGenerator{overrideProvider: overrideProvider, enableSCMProviders: true} } func (g *SCMProviderGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration { @@ -58,6 +68,46 @@ func (g *SCMProviderGenerator) GetTemplate(appSetGenerator *argoprojiov1alpha1.A return &appSetGenerator.SCMProvider.Template } +var ErrSCMProvidersDisabled = errors.New("scm providers are disabled") + +type ErrDisallowedSCMProvider struct { + Provider string + Allowed []string +} + +func NewErrDisallowedSCMProvider(provider string, allowed []string) ErrDisallowedSCMProvider { + return ErrDisallowedSCMProvider{ + Provider: provider, + Allowed: allowed, + } +} + +func (e ErrDisallowedSCMProvider) Error() string { + return fmt.Sprintf("scm provider %q not allowed, must use one of the following: %s", e.Provider, strings.Join(e.Allowed, ", ")) +} + +func ScmProviderAllowed(applicationSetInfo *argoprojiov1alpha1.ApplicationSet, generator SCMGeneratorWithCustomApiUrl, allowedScmProviders []string) error { + url := generator.CustomApiUrl() + + if url == "" || len(allowedScmProviders) == 0 { + return nil + } + + for _, allowedScmProvider := range allowedScmProviders { + if url == allowedScmProvider { + return nil + } + } + + log.WithFields(log.Fields{ + common.SecurityField: common.SecurityMedium, + "applicationset": applicationSetInfo.Name, + "appSetNamespace": applicationSetInfo.Namespace, + }).Debugf("attempted to use disallowed SCM %q, must use one of the following: %s", url, strings.Join(allowedScmProviders, ", ")) + + return NewErrDisallowedSCMProvider(url, allowedScmProviders) +} + func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) { if appSetGenerator == nil { return nil, EmptyAppSetGeneratorError @@ -67,10 +117,18 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha return nil, EmptyAppSetGeneratorError } - ctx := context.Background() + if !g.enableSCMProviders { + return nil, ErrSCMProvidersDisabled + } // Create the SCM provider helper. providerConfig := appSetGenerator.SCMProvider + + if err := ScmProviderAllowed(applicationSetInfo, providerConfig, g.allowedSCMProviders); err != nil { + return nil, fmt.Errorf("scm provider not allowed: %w", err) + } + + ctx := context.Background() var provider scm_provider.SCMProviderService if g.overrideProvider != nil { provider = g.overrideProvider @@ -85,7 +143,7 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha if err != nil { return nil, fmt.Errorf("error fetching Gitlab token: %v", err) } - provider, err = scm_provider.NewGitlabProvider(ctx, providerConfig.Gitlab.Group, token, providerConfig.Gitlab.API, providerConfig.Gitlab.AllBranches, providerConfig.Gitlab.IncludeSubgroups) + provider, err = scm_provider.NewGitlabProvider(ctx, providerConfig.Gitlab.Group, token, providerConfig.Gitlab.API, providerConfig.Gitlab.AllBranches, providerConfig.Gitlab.IncludeSubgroups, providerConfig.Gitlab.WillIncludeSharedProjects(), providerConfig.Gitlab.Insecure, g.scmRootCAPath, providerConfig.Gitlab.Topic) if err != nil { return nil, fmt.Errorf("error initializing Gitlab service: %v", err) } @@ -131,6 +189,12 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha if err != nil { return nil, fmt.Errorf("error initializing Bitbucket cloud service: %v", err) } + } else if providerConfig.AWSCodeCommit != nil { + var awsErr error + provider, awsErr = scm_provider.NewAWSCodeCommitProvider(ctx, providerConfig.AWSCodeCommit.TagFilters, providerConfig.AWSCodeCommit.Role, providerConfig.AWSCodeCommit.Region, providerConfig.AWSCodeCommit.AllBranches) + if awsErr != nil { + return nil, fmt.Errorf("error initializing AWS codecommit service: %v", awsErr) + } } else { return nil, fmt.Errorf("no SCM provider implementation configured") } @@ -140,26 +204,40 @@ func (g *SCMProviderGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha if err != nil { return nil, fmt.Errorf("error listing repos: %v", err) } - params := make([]map[string]interface{}, 0, len(repos)) + paramsArray := make([]map[string]interface{}, 0, len(repos)) var shortSHALength int + var shortSHALength7 int for _, repo := range repos { shortSHALength = 8 if len(repo.SHA) < 8 { shortSHALength = len(repo.SHA) } - params = append(params, map[string]interface{}{ + shortSHALength7 = 7 + if len(repo.SHA) < 7 { + shortSHALength7 = len(repo.SHA) + } + + params := map[string]interface{}{ "organization": repo.Organization, "repository": repo.Repository, "url": repo.URL, "branch": repo.Branch, "sha": repo.SHA, "short_sha": repo.SHA[:shortSHALength], + "short_sha_7": repo.SHA[:shortSHALength7], "labels": strings.Join(repo.Labels, ","), "branchNormalized": utils.SanitizeName(repo.Branch), - }) + } + + err := appendTemplatedValues(appSetGenerator.SCMProvider.Values, params, applicationSetInfo.Spec.GoTemplate, applicationSetInfo.Spec.GoTemplateOptions) + if err != nil { + return nil, fmt.Errorf("failed to append templated values: %w", err) + } + + paramsArray = append(paramsArray, params) } - return params, nil + return paramsArray, nil } func (g *SCMProviderGenerator) getSecretRef(ctx context.Context, ref *argoprojiov1alpha1.SecretRef, namespace string) (string, error) { diff --git a/applicationset/generators/scm_provider_test.go b/applicationset/generators/scm_provider_test.go index bcc4490194285..c438aa8f646fe 100644 --- a/applicationset/generators/scm_provider_test.go +++ b/applicationset/generators/scm_provider_test.go @@ -80,38 +80,234 @@ func TestSCMProviderGetSecretRef(t *testing.T) { } func TestSCMProviderGenerateParams(t *testing.T) { - mockProvider := &scm_provider.MockProvider{ - Repos: []*scm_provider.Repository{ - { - Organization: "myorg", - Repository: "repo1", - URL: "git@github.com:myorg/repo1.git", - Branch: "main", - SHA: "0bc57212c3cbbec69d20b34c507284bd300def5b", - Labels: []string{"prod", "staging"}, + cases := []struct { + name string + repos []*scm_provider.Repository + values map[string]string + expected []map[string]interface{} + expectedError error + }{ + { + name: "Multiple repos with labels", + repos: []*scm_provider.Repository{ + { + Organization: "myorg", + Repository: "repo1", + URL: "git@github.com:myorg/repo1.git", + Branch: "main", + SHA: "0bc57212c3cbbec69d20b34c507284bd300def5b", + Labels: []string{"prod", "staging"}, + }, + { + Organization: "myorg", + Repository: "repo2", + URL: "git@github.com:myorg/repo2.git", + Branch: "main", + SHA: "59d0", + }, + }, + expected: []map[string]interface{}{ + { + "organization": "myorg", + "repository": "repo1", + "url": "git@github.com:myorg/repo1.git", + "branch": "main", + "branchNormalized": "main", + "sha": "0bc57212c3cbbec69d20b34c507284bd300def5b", + "short_sha": "0bc57212", + "short_sha_7": "0bc5721", + "labels": "prod,staging", + }, + { + "organization": "myorg", + "repository": "repo2", + "url": "git@github.com:myorg/repo2.git", + "branch": "main", + "branchNormalized": "main", + "sha": "59d0", + "short_sha": "59d0", + "short_sha_7": "59d0", + "labels": "", + }, + }, + }, + { + name: "Value interpolation", + repos: []*scm_provider.Repository{ + { + Organization: "myorg", + Repository: "repo3", + URL: "git@github.com:myorg/repo3.git", + Branch: "main", + SHA: "0bc57212c3cbbec69d20b34c507284bd300def5b", + Labels: []string{"prod", "staging"}, + }, + }, + values: map[string]string{ + "foo": "bar", + "should_i_force_push_to": "{{ branch }}?", }, - { - Organization: "myorg", - Repository: "repo2", - URL: "git@github.com:myorg/repo2.git", - Branch: "main", - SHA: "59d0", + expected: []map[string]interface{}{ + { + "organization": "myorg", + "repository": "repo3", + "url": "git@github.com:myorg/repo3.git", + "branch": "main", + "branchNormalized": "main", + "sha": "0bc57212c3cbbec69d20b34c507284bd300def5b", + "short_sha": "0bc57212", + "short_sha_7": "0bc5721", + "labels": "prod,staging", + "values.foo": "bar", + "values.should_i_force_push_to": "main?", + }, }, }, } - gen := &SCMProviderGenerator{overrideProvider: mockProvider} - params, err := gen.GenerateParams(&argoprojiov1alpha1.ApplicationSetGenerator{ - SCMProvider: &argoprojiov1alpha1.SCMProviderGenerator{}, - }, nil) - assert.Nil(t, err) - assert.Len(t, params, 2) - assert.Equal(t, "myorg", params[0]["organization"]) - assert.Equal(t, "repo1", params[0]["repository"]) - assert.Equal(t, "git@github.com:myorg/repo1.git", params[0]["url"]) - assert.Equal(t, "main", params[0]["branch"]) - assert.Equal(t, "0bc57212c3cbbec69d20b34c507284bd300def5b", params[0]["sha"]) - assert.Equal(t, "0bc57212", params[0]["short_sha"]) - assert.Equal(t, "59d0", params[1]["short_sha"]) - assert.Equal(t, "prod,staging", params[0]["labels"]) - assert.Equal(t, "repo2", params[1]["repository"]) + + for _, testCase := range cases { + testCaseCopy := testCase + + t.Run(testCaseCopy.name, func(t *testing.T) { + t.Parallel() + + mockProvider := &scm_provider.MockProvider{ + Repos: testCaseCopy.repos, + } + scmGenerator := &SCMProviderGenerator{overrideProvider: mockProvider, enableSCMProviders: true} + applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "set", + }, + Spec: argoprojiov1alpha1.ApplicationSetSpec{ + Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{ + SCMProvider: &argoprojiov1alpha1.SCMProviderGenerator{ + Values: testCaseCopy.values, + }, + }}, + }, + } + + got, err := scmGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo) + + if testCaseCopy.expectedError != nil { + assert.EqualError(t, err, testCaseCopy.expectedError.Error()) + } else { + assert.NoError(t, err) + assert.Equal(t, testCaseCopy.expected, got) + } + + }) + } +} + +func TestAllowedSCMProvider(t *testing.T) { + cases := []struct { + name string + providerConfig *argoprojiov1alpha1.SCMProviderGenerator + expectedError error + }{ + { + name: "Error Github", + providerConfig: &argoprojiov1alpha1.SCMProviderGenerator{ + Github: &argoprojiov1alpha1.SCMProviderGeneratorGithub{ + API: "https://myservice.mynamespace.svc.cluster.local", + }, + }, + expectedError: &ErrDisallowedSCMProvider{}, + }, + { + name: "Error Gitlab", + providerConfig: &argoprojiov1alpha1.SCMProviderGenerator{ + Gitlab: &argoprojiov1alpha1.SCMProviderGeneratorGitlab{ + API: "https://myservice.mynamespace.svc.cluster.local", + }, + }, + expectedError: &ErrDisallowedSCMProvider{}, + }, + { + name: "Error Gitea", + providerConfig: &argoprojiov1alpha1.SCMProviderGenerator{ + Gitea: &argoprojiov1alpha1.SCMProviderGeneratorGitea{ + API: "https://myservice.mynamespace.svc.cluster.local", + }, + }, + expectedError: &ErrDisallowedSCMProvider{}, + }, + { + name: "Error Bitbucket", + providerConfig: &argoprojiov1alpha1.SCMProviderGenerator{ + BitbucketServer: &argoprojiov1alpha1.SCMProviderGeneratorBitbucketServer{ + API: "https://myservice.mynamespace.svc.cluster.local", + }, + }, + expectedError: &ErrDisallowedSCMProvider{}, + }, + { + name: "Error AzureDevops", + providerConfig: &argoprojiov1alpha1.SCMProviderGenerator{ + AzureDevOps: &argoprojiov1alpha1.SCMProviderGeneratorAzureDevOps{ + API: "https://myservice.mynamespace.svc.cluster.local", + }, + }, + expectedError: &ErrDisallowedSCMProvider{}, + }, + } + + for _, testCase := range cases { + testCaseCopy := testCase + + t.Run(testCaseCopy.name, func(t *testing.T) { + t.Parallel() + + scmGenerator := &SCMProviderGenerator{ + allowedSCMProviders: []string{ + "github.myorg.com", + "gitlab.myorg.com", + "gitea.myorg.com", + "bitbucket.myorg.com", + "azuredevops.myorg.com", + }, + enableSCMProviders: true, + } + + applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "set", + }, + Spec: argoprojiov1alpha1.ApplicationSetSpec{ + Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{ + SCMProvider: testCaseCopy.providerConfig, + }}, + }, + } + + _, err := scmGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo) + + assert.Error(t, err, "Must return an error") + assert.ErrorAs(t, err, testCaseCopy.expectedError) + }) + } +} + +func TestSCMProviderDisabled_SCMGenerator(t *testing.T) { + generator := &SCMProviderGenerator{enableSCMProviders: false} + + applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "set", + }, + Spec: argoprojiov1alpha1.ApplicationSetSpec{ + Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{ + SCMProvider: &argoprojiov1alpha1.SCMProviderGenerator{ + Github: &argoprojiov1alpha1.SCMProviderGeneratorGithub{ + API: "https://myservice.mynamespace.svc.cluster.local", + }, + }, + }}, + }, + } + + _, err := generator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo) + assert.ErrorIs(t, err, ErrSCMProvidersDisabled) } diff --git a/applicationset/generators/scm_utils.go b/applicationset/generators/scm_utils.go new file mode 100644 index 0000000000000..51ac99d9b7e49 --- /dev/null +++ b/applicationset/generators/scm_utils.go @@ -0,0 +1,5 @@ +package generators + +type SCMGeneratorWithCustomApiUrl interface { + CustomApiUrl() string +} diff --git a/applicationset/generators/value_interpolation.go b/applicationset/generators/value_interpolation.go new file mode 100644 index 0000000000000..05a078d42f782 --- /dev/null +++ b/applicationset/generators/value_interpolation.go @@ -0,0 +1,43 @@ +package generators + +import ( + "fmt" +) + +func appendTemplatedValues(values map[string]string, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) error { + // We create a local map to ensure that we do not fall victim to a billion-laughs attack. We iterate through the + // cluster values map and only replace values in said map if it has already been allowlisted in the params map. + // Once we iterate through all the cluster values we can then safely merge the `tmp` map into the main params map. + tmp := map[string]interface{}{} + + for key, value := range values { + result, err := replaceTemplatedString(value, params, useGoTemplate, goTemplateOptions) + + if err != nil { + return fmt.Errorf("failed to replace templated string: %w", err) + } + + if useGoTemplate { + if tmp["values"] == nil { + tmp["values"] = map[string]string{} + } + tmp["values"].(map[string]string)[key] = result + } else { + tmp[fmt.Sprintf("values.%s", key)] = result + } + } + + for key, value := range tmp { + params[key] = value + } + + return nil +} + +func replaceTemplatedString(value string, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (string, error) { + replacedTmplStr, err := render.Replace(value, params, useGoTemplate, goTemplateOptions) + if err != nil { + return "", fmt.Errorf("failed to replace templated string with rendered values: %w", err) + } + return replacedTmplStr, nil +} diff --git a/applicationset/generators/value_interpolation_test.go b/applicationset/generators/value_interpolation_test.go new file mode 100644 index 0000000000000..8aa57dc0c0e65 --- /dev/null +++ b/applicationset/generators/value_interpolation_test.go @@ -0,0 +1,125 @@ +package generators + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestValueInterpolation(t *testing.T) { + testCases := []struct { + name string + values map[string]string + params map[string]interface{} + expected map[string]interface{} + }{ + { + name: "Simple interpolation", + values: map[string]string{ + "hello": "{{ world }}", + }, + params: map[string]interface{}{ + "world": "world!", + }, + expected: map[string]interface{}{ + "world": "world!", + "values.hello": "world!", + }, + }, + { + name: "Non-existent", + values: map[string]string{ + "non-existent": "{{ non-existent }}", + }, + params: map[string]interface{}{}, + expected: map[string]interface{}{ + "values.non-existent": "{{ non-existent }}", + }, + }, + { + name: "Billion laughs", + values: map[string]string{ + "lol1": "lol", + "lol2": "{{values.lol1}}{{values.lol1}}", + "lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}", + }, + params: map[string]interface{}{}, + expected: map[string]interface{}{ + "values.lol1": "lol", + "values.lol2": "{{values.lol1}}{{values.lol1}}", + "values.lol3": "{{values.lol2}}{{values.lol2}}{{values.lol2}}", + }, + }, + } + + for _, testCase := range testCases { + + t.Run(testCase.name, func(t *testing.T) { + err := appendTemplatedValues(testCase.values, testCase.params, false, nil) + assert.NoError(t, err) + assert.EqualValues(t, testCase.expected, testCase.params) + }) + } +} + +func TestValueInterpolationWithGoTemplating(t *testing.T) { + testCases := []struct { + name string + values map[string]string + params map[string]interface{} + expected map[string]interface{} + }{ + { + name: "Simple interpolation", + values: map[string]string{ + "hello": "{{ .world }}", + }, + params: map[string]interface{}{ + "world": "world!", + }, + expected: map[string]interface{}{ + "world": "world!", + "values": map[string]string{ + "hello": "world!", + }, + }, + }, + { + name: "Non-existent to default", + values: map[string]string{ + "non_existent": "{{ default \"bar\" .non_existent }}", + }, + params: map[string]interface{}{}, + expected: map[string]interface{}{ + "values": map[string]string{ + "non_existent": "bar", + }, + }, + }, + { + name: "Billion laughs", + values: map[string]string{ + "lol1": "lol", + "lol2": "{{.values.lol1}}{{.values.lol1}}", + "lol3": "{{.values.lol2}}{{.values.lol2}}{{.values.lol2}}", + }, + params: map[string]interface{}{}, + expected: map[string]interface{}{ + "values": map[string]string{ + "lol1": "lol", + "lol2": "", + "lol3": "", + }, + }, + }, + } + + for _, testCase := range testCases { + + t.Run(testCase.name, func(t *testing.T) { + err := appendTemplatedValues(testCase.values, testCase.params, true, nil) + assert.NoError(t, err) + assert.EqualValues(t, testCase.expected, testCase.params) + }) + } +} diff --git a/applicationset/services/internal/http/client.go b/applicationset/services/internal/http/client.go new file mode 100644 index 0000000000000..00bcf32f3204f --- /dev/null +++ b/applicationset/services/internal/http/client.go @@ -0,0 +1,161 @@ +package http + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "strings" + "time" +) + +const ( + userAgent = "argocd-applicationset" + defaultTimeout = 30 +) + +type Client struct { + // URL is the URL used for API requests. + baseURL string + + // UserAgent is the user agent to include in HTTP requests. + UserAgent string + + // Token is used to make authenticated API calls. + token string + + // Client is an HTTP client used to communicate with the API. + client *http.Client +} + +type ErrorResponse struct { + Body []byte + Response *http.Response + Message string +} + +func NewClient(baseURL string, options ...ClientOptionFunc) (*Client, error) { + client, err := newClient(baseURL, options...) + if err != nil { + return nil, err + } + return client, nil +} + +func newClient(baseURL string, options ...ClientOptionFunc) (*Client, error) { + c := &Client{baseURL: baseURL, UserAgent: userAgent} + + // Configure the HTTP client. + c.client = &http.Client{ + Timeout: time.Duration(defaultTimeout) * time.Second, + } + + // Apply any given client options. + for _, fn := range options { + if fn == nil { + continue + } + if err := fn(c); err != nil { + return nil, err + } + } + + return c, nil +} + +func (c *Client) NewRequest(method, path string, body interface{}, options []ClientOptionFunc) (*http.Request, error) { + + // Make sure the given URL end with a slash + if !strings.HasSuffix(c.baseURL, "/") { + c.baseURL += "/" + } + + var buf io.ReadWriter + if body != nil { + buf = &bytes.Buffer{} + enc := json.NewEncoder(buf) + enc.SetEscapeHTML(false) + err := enc.Encode(body) + if err != nil { + return nil, err + } + } + + req, err := http.NewRequest(method, c.baseURL+path, buf) + if err != nil { + return nil, err + } + + if body != nil { + req.Header.Set("Content-Type", "application/json") + } + + if len(c.token) != 0 { + req.Header.Set("Authorization", "Bearer "+c.token) + } + + if c.UserAgent != "" { + req.Header.Set("User-Agent", c.UserAgent) + } + + return req, nil +} + +func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*http.Response, error) { + resp, err := c.client.Do(req) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + + if err := CheckResponse(resp); err != nil { + return resp, err + } + + switch v := v.(type) { + case nil: + case io.Writer: + _, err = io.Copy(v, resp.Body) + default: + buf := new(bytes.Buffer) + teeReader := io.TeeReader(resp.Body, buf) + decErr := json.NewDecoder(teeReader).Decode(v) + if decErr == io.EOF { + decErr = nil // ignore EOF errors caused by empty response body + } + if decErr != nil { + err = fmt.Errorf("%s: %s", decErr.Error(), buf.String()) + } + } + return resp, err +} + +// CheckResponse checks the API response for errors, and returns them if present. +func CheckResponse(resp *http.Response) error { + + if c := resp.StatusCode; 200 <= c && c <= 299 { + return nil + } + + data, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("API error with status code %d: %v", resp.StatusCode, err) + } + + var raw map[string]interface{} + if err := json.Unmarshal(data, &raw); err != nil { + return fmt.Errorf("API error with status code %d: %s", resp.StatusCode, string(data)) + } + + message := "" + if value, ok := raw["message"].(string); ok { + message = value + } else if value, ok := raw["error"].(string); ok { + message = value + } + + return fmt.Errorf("API error with status code %d: %s", resp.StatusCode, message) +} diff --git a/applicationset/services/internal/http/client_options.go b/applicationset/services/internal/http/client_options.go new file mode 100644 index 0000000000000..ec388c9a80605 --- /dev/null +++ b/applicationset/services/internal/http/client_options.go @@ -0,0 +1,22 @@ +package http + +import "time" + +// ClientOptionFunc can be used to customize a new Restful API client. +type ClientOptionFunc func(*Client) error + +// WithToken is an option for NewClient to set token +func WithToken(token string) ClientOptionFunc { + return func(c *Client) error { + c.token = token + return nil + } +} + +// WithTimeout can be used to configure a custom timeout for requests. +func WithTimeout(timeout int) ClientOptionFunc { + return func(c *Client) error { + c.client.Timeout = time.Duration(timeout) * time.Second + return nil + } +} diff --git a/applicationset/services/internal/http/client_test.go b/applicationset/services/internal/http/client_test.go new file mode 100644 index 0000000000000..ca2c916177fee --- /dev/null +++ b/applicationset/services/internal/http/client_test.go @@ -0,0 +1,163 @@ +package http + +import ( + "bytes" + "context" + "fmt" + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestClient(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _, err := w.Write([]byte("Hello, World!")) + if err != nil { + assert.NoError(t, fmt.Errorf("Error Write %v", err)) + } + })) + defer server.Close() + + var clientOptionFns []ClientOptionFunc + _, err := NewClient(server.URL, clientOptionFns...) + + if err != nil { + t.Fatalf("Failed to create client: %v", err) + } +} + +func TestClientDo(t *testing.T) { + ctx := context.Background() + + for _, c := range []struct { + name string + params map[string]string + content []byte + fakeServer *httptest.Server + clientOptionFns []ClientOptionFunc + expected []map[string]interface{} + expectedCode int + expectedError error + }{ + { + name: "Simple", + params: map[string]string{ + "pkey1": "val1", + "pkey2": "val2", + }, + fakeServer: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _, err := w.Write([]byte(`[{ + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123 + }]`)) + if err != nil { + assert.NoError(t, fmt.Errorf("Error Write %v", err)) + } + })), + clientOptionFns: nil, + expected: []map[string]interface{}{ + { + "key1": "val1", + "key2": map[string]interface{}{ + "key2_1": "val2_1", + "key2_2": map[string]interface{}{ + "key2_2_1": "val2_2_1", + }, + }, + "key3": float64(123), + }, + }, + expectedCode: 200, + expectedError: nil, + }, + { + name: "With Token", + params: map[string]string{ + "pkey1": "val1", + "pkey2": "val2", + }, + fakeServer: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + authHeader := r.Header.Get("Authorization") + if authHeader != "Bearer "+string("test-token") { + w.WriteHeader(http.StatusUnauthorized) + return + } + w.WriteHeader(http.StatusOK) + _, err := w.Write([]byte(`[{ + "key1": "val1", + "key2": { + "key2_1": "val2_1", + "key2_2": { + "key2_2_1": "val2_2_1" + } + }, + "key3": 123 + }]`)) + if err != nil { + assert.NoError(t, fmt.Errorf("Error Write %v", err)) + } + })), + clientOptionFns: nil, + expected: []map[string]interface{}(nil), + expectedCode: 401, + expectedError: fmt.Errorf("API error with status code 401: "), + }, + } { + cc := c + t.Run(cc.name, func(t *testing.T) { + defer cc.fakeServer.Close() + + client, err := NewClient(cc.fakeServer.URL, cc.clientOptionFns...) + + if err != nil { + t.Fatalf("NewClient returned unexpected error: %v", err) + } + + req, err := client.NewRequest("POST", "", cc.params, nil) + + if err != nil { + t.Fatalf("NewRequest returned unexpected error: %v", err) + } + + var data []map[string]interface{} + + resp, err := client.Do(ctx, req, &data) + + if cc.expectedError != nil { + assert.EqualError(t, err, cc.expectedError.Error()) + } else { + assert.Equal(t, resp.StatusCode, cc.expectedCode) + assert.Equal(t, data, cc.expected) + assert.NoError(t, err) + } + }) + } +} + +func TestCheckResponse(t *testing.T) { + resp := &http.Response{ + StatusCode: http.StatusBadRequest, + Body: io.NopCloser(bytes.NewBufferString(`{"error":"invalid_request","description":"Invalid token"}`)), + } + + err := CheckResponse(resp) + if err == nil { + t.Error("Expected an error, got nil") + } + + expected := "API error with status code 400: invalid_request" + if err.Error() != expected { + t.Errorf("Expected error '%s', got '%s'", expected, err.Error()) + } +} diff --git a/applicationset/services/mocks/Repos.go b/applicationset/services/mocks/Repos.go new file mode 100644 index 0000000000000..b7620b22f08bb --- /dev/null +++ b/applicationset/services/mocks/Repos.go @@ -0,0 +1,81 @@ +// Code generated by mockery v2.25.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" +) + +// Repos is an autogenerated mock type for the Repos type +type Repos struct { + mock.Mock +} + +// 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, bool) ([]string, error)); ok { + return rf(ctx, repoURL, revision, noRevisionCache) + } + 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, bool) error); ok { + r1 = rf(ctx, repoURL, revision, noRevisionCache) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// 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, 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, 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, bool) error); ok { + r1 = rf(ctx, repoURL, revision, pattern, noRevisionCache) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewRepos interface { + mock.TestingT + Cleanup(func()) +} + +// NewRepos creates a new instance of Repos. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewRepos(t mockConstructorTestingTNewRepos) *Repos { + mock := &Repos{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/applicationset/services/mocks/RepositoryDB.go b/applicationset/services/mocks/RepositoryDB.go new file mode 100644 index 0000000000000..9d6240d342776 --- /dev/null +++ b/applicationset/services/mocks/RepositoryDB.go @@ -0,0 +1,57 @@ +// Code generated by mockery v2.21.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + v1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" +) + +// RepositoryDB is an autogenerated mock type for the RepositoryDB type +type RepositoryDB struct { + mock.Mock +} + +// GetRepository provides a mock function with given fields: ctx, url +func (_m *RepositoryDB) GetRepository(ctx context.Context, url string) (*v1alpha1.Repository, error) { + ret := _m.Called(ctx, url) + + var r0 *v1alpha1.Repository + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*v1alpha1.Repository, error)); ok { + return rf(ctx, url) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *v1alpha1.Repository); ok { + r0 = rf(ctx, url) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v1alpha1.Repository) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(ctx, url) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewRepositoryDB interface { + mock.TestingT + Cleanup(func()) +} + +// NewRepositoryDB creates a new instance of RepositoryDB. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewRepositoryDB(t mockConstructorTestingTNewRepositoryDB) *RepositoryDB { + mock := &RepositoryDB{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/applicationset/services/plugin/plugin_service.go b/applicationset/services/plugin/plugin_service.go new file mode 100644 index 0000000000000..95573e0942407 --- /dev/null +++ b/applicationset/services/plugin/plugin_service.go @@ -0,0 +1,73 @@ +package plugin + +import ( + "context" + "fmt" + "net/http" + + internalhttp "github.com/argoproj/argo-cd/v2/applicationset/services/internal/http" + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" +) + +// ServiceRequest is the request object sent to the plugin service. +type ServiceRequest struct { + // ApplicationSetName is the appSetName of the ApplicationSet for which we're requesting parameters. Useful for logging in + // the plugin service. + ApplicationSetName string `json:"applicationSetName"` + // Input is the map of parameters set in the ApplicationSet spec for this generator. + Input v1alpha1.PluginInput `json:"input"` +} + +type Output struct { + // Parameters is the list of parameter sets returned by the plugin. + Parameters []map[string]interface{} `json:"parameters"` +} + +// ServiceResponse is the response object returned by the plugin service. +type ServiceResponse struct { + // Output is the map of outputs returned by the plugin. + Output Output `json:"output"` +} + +type Service struct { + client *internalhttp.Client + appSetName string +} + +func NewPluginService(ctx context.Context, appSetName string, baseURL string, token string, requestTimeout int) (*Service, error) { + var clientOptionFns []internalhttp.ClientOptionFunc + + clientOptionFns = append(clientOptionFns, internalhttp.WithToken(token)) + + if requestTimeout != 0 { + clientOptionFns = append(clientOptionFns, internalhttp.WithTimeout(requestTimeout)) + } + + client, err := internalhttp.NewClient(baseURL, clientOptionFns...) + if err != nil { + return nil, fmt.Errorf("error creating plugin client: %v", err) + } + + return &Service{ + client: client, + appSetName: appSetName, + }, nil +} + +func (p *Service) List(ctx context.Context, parameters v1alpha1.PluginParameters) (*ServiceResponse, error) { + req, err := p.client.NewRequest(http.MethodPost, "api/v1/getparams.execute", ServiceRequest{ApplicationSetName: p.appSetName, Input: v1alpha1.PluginInput{Parameters: parameters}}, nil) + + if err != nil { + return nil, fmt.Errorf("NewRequest returned unexpected error: %v", err) + } + + var data ServiceResponse + + _, err = p.client.Do(ctx, req, &data) + + if err != nil { + return nil, fmt.Errorf("error get api '%s': %v", p.appSetName, err) + } + + return &data, err +} diff --git a/applicationset/services/plugin/plugin_service_test.go b/applicationset/services/plugin/plugin_service_test.go new file mode 100644 index 0000000000000..6dc81d33df71f --- /dev/null +++ b/applicationset/services/plugin/plugin_service_test.go @@ -0,0 +1,52 @@ +package plugin + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPlugin(t *testing.T) { + expectedJSON := `{"parameters": [{"number":123,"digest":"sha256:942ae2dfd73088b54d7151a3c3fd5af038a51c50029bfcfd21f1e650d9579967"},{"number":456,"digest":"sha256:224e68cc69566e5cbbb76034b3c42cd2ed57c1a66720396e1c257794cb7d68c1"}]}` + token := "0bc57212c3cbbec69d20b34c507284bd300def5b" + + handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + authHeader := r.Header.Get("Authorization") + if authHeader != "Bearer "+token { + w.WriteHeader(http.StatusUnauthorized) + return + } + _, err := w.Write([]byte(expectedJSON)) + + if err != nil { + assert.NoError(t, fmt.Errorf("Error Write %v", err)) + } + }) + ts := httptest.NewServer(handler) + defer ts.Close() + + client, err := NewPluginService(context.Background(), "plugin-test", ts.URL, token, 0) + + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + data, err := client.List(context.Background(), nil) + + if err != nil { + t.Errorf("unexpected error: %v", err) + } + + var expectedData ServiceResponse + err = json.Unmarshal([]byte(expectedJSON), &expectedData) + if err != nil { + t.Fatal(err) + } + assert.Equal(t, &expectedData, data) +} diff --git a/applicationset/services/plugin/utils.go b/applicationset/services/plugin/utils.go new file mode 100644 index 0000000000000..26e38e492200d --- /dev/null +++ b/applicationset/services/plugin/utils.go @@ -0,0 +1,21 @@ +package plugin + +import ( + "fmt" + "strings" + + "github.com/argoproj/argo-cd/v2/common" +) + +// ParseSecretKey retrieves secret appSetName if different from common ArgoCDSecretName. +func ParseSecretKey(key string) (secretName string, tokenKey string) { + if strings.Contains(key, ":") { + parts := strings.Split(key, ":") + secretName = parts[0][1:] + tokenKey = fmt.Sprintf("$%s", parts[1]) + } else { + secretName = common.ArgoCDSecretName + tokenKey = key + } + return secretName, tokenKey +} diff --git a/applicationset/services/plugin/utils_test.go b/applicationset/services/plugin/utils_test.go new file mode 100644 index 0000000000000..c364d606392e4 --- /dev/null +++ b/applicationset/services/plugin/utils_test.go @@ -0,0 +1,17 @@ +package plugin + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParseSecretKey(t *testing.T) { + secretName, tokenKey := ParseSecretKey("#my-secret:my-token") + assert.Equal(t, "my-secret", secretName) + assert.Equal(t, "$my-token", tokenKey) + + secretName, tokenKey = ParseSecretKey("#my-secret") + assert.Equal(t, "argocd-secret", secretName) + assert.Equal(t, "#my-secret", tokenKey) +} diff --git a/applicationset/services/pull_request/azure_devops.go b/applicationset/services/pull_request/azure_devops.go new file mode 100644 index 0000000000000..9090b829ca0c2 --- /dev/null +++ b/applicationset/services/pull_request/azure_devops.go @@ -0,0 +1,145 @@ +package pull_request + +import ( + "context" + "fmt" + "strings" + + "github.com/microsoft/azure-devops-go-api/azuredevops" + core "github.com/microsoft/azure-devops-go-api/azuredevops/core" + git "github.com/microsoft/azure-devops-go-api/azuredevops/git" +) + +const AZURE_DEVOPS_DEFAULT_URL = "https://dev.azure.com" + +type AzureDevOpsClientFactory interface { + // Returns an Azure Devops Client interface. + GetClient(ctx context.Context) (git.Client, error) +} + +type devopsFactoryImpl struct { + connection *azuredevops.Connection +} + +func (factory *devopsFactoryImpl) GetClient(ctx context.Context) (git.Client, error) { + gitClient, err := git.NewClient(ctx, factory.connection) + if err != nil { + return nil, fmt.Errorf("failed to get new Azure DevOps git client for pull request generator: %w", err) + } + return gitClient, nil +} + +type AzureDevOpsService struct { + clientFactory AzureDevOpsClientFactory + project string + repo string + labels []string +} + +var _ PullRequestService = (*AzureDevOpsService)(nil) +var _ AzureDevOpsClientFactory = &devopsFactoryImpl{} + +func NewAzureDevOpsService(ctx context.Context, token, url, organization, project, repo string, labels []string) (PullRequestService, error) { + organizationUrl := buildURL(url, organization) + + var connection *azuredevops.Connection + if token == "" { + connection = azuredevops.NewAnonymousConnection(organizationUrl) + } else { + connection = azuredevops.NewPatConnection(organizationUrl, token) + } + + return &AzureDevOpsService{ + clientFactory: &devopsFactoryImpl{connection: connection}, + project: project, + repo: repo, + labels: labels, + }, nil +} + +func (a *AzureDevOpsService) List(ctx context.Context) ([]*PullRequest, error) { + client, err := a.clientFactory.GetClient(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get Azure DevOps client: %w", err) + } + + args := git.GetPullRequestsByProjectArgs{ + Project: &a.project, + SearchCriteria: &git.GitPullRequestSearchCriteria{}, + } + + azurePullRequests, err := client.GetPullRequestsByProject(ctx, args) + if err != nil { + return nil, fmt.Errorf("failed to get pull requests by project: %w", err) + } + + pullRequests := []*PullRequest{} + + for _, pr := range *azurePullRequests { + if pr.Repository == nil || + pr.Repository.Name == nil || + pr.PullRequestId == nil || + pr.SourceRefName == nil || + pr.LastMergeSourceCommit == nil || + pr.LastMergeSourceCommit.CommitId == nil { + continue + } + + azureDevOpsLabels := convertLabels(pr.Labels) + if !containAzureDevOpsLabels(a.labels, azureDevOpsLabels) { + continue + } + + if *pr.Repository.Name == a.repo { + pullRequests = append(pullRequests, &PullRequest{ + Number: *pr.PullRequestId, + Branch: strings.Replace(*pr.SourceRefName, "refs/heads/", "", 1), + HeadSHA: *pr.LastMergeSourceCommit.CommitId, + Labels: azureDevOpsLabels, + }) + } + } + + return pullRequests, nil +} + +// convertLabels converts WebApiTagDefinitions to strings +func convertLabels(tags *[]core.WebApiTagDefinition) []string { + if tags == nil { + return []string{} + } + labelStrings := make([]string, len(*tags)) + for i, label := range *tags { + labelStrings[i] = *label.Name + } + return labelStrings +} + +// containAzureDevOpsLabels returns true if gotLabels contains expectedLabels +func containAzureDevOpsLabels(expectedLabels []string, gotLabels []string) bool { + for _, expected := range expectedLabels { + found := false + for _, got := range gotLabels { + if expected == got { + found = true + break + } + } + if !found { + return false + } + } + return true +} + +func buildURL(url, organization string) string { + if url == "" { + url = AZURE_DEVOPS_DEFAULT_URL + } + separator := "" + if !strings.HasSuffix(url, "/") { + separator = "/" + } + devOpsURL := fmt.Sprintf("%s%s%s", url, separator, organization) + return devOpsURL +} diff --git a/applicationset/services/pull_request/azure_devops_test.go b/applicationset/services/pull_request/azure_devops_test.go new file mode 100644 index 0000000000000..5ed8f4de78b9d --- /dev/null +++ b/applicationset/services/pull_request/azure_devops_test.go @@ -0,0 +1,221 @@ +package pull_request + +import ( + "context" + "testing" + + "github.com/microsoft/azure-devops-go-api/azuredevops/core" + git "github.com/microsoft/azure-devops-go-api/azuredevops/git" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + azureMock "github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider/azure_devops/git/mocks" +) + +func createBoolPtr(x bool) *bool { + return &x +} + +func createStringPtr(x string) *string { + return &x +} + +func createIntPtr(x int) *int { + return &x +} + +func createLabelsPtr(x []core.WebApiTagDefinition) *[]core.WebApiTagDefinition { + return &x +} + +type AzureClientFactoryMock struct { + mock *mock.Mock +} + +func (m *AzureClientFactoryMock) GetClient(ctx context.Context) (git.Client, error) { + args := m.mock.Called(ctx) + + var client git.Client + c := args.Get(0) + if c != nil { + client = c.(git.Client) + } + + var err error + if len(args) > 1 { + if e, ok := args.Get(1).(error); ok { + err = e + } + } + + return client, err +} + +func TestListPullRequest(t *testing.T) { + teamProject := "myorg_project" + repoName := "myorg_project_repo" + pr_id := 123 + pr_head_sha := "cd4973d9d14a08ffe6b641a89a68891d6aac8056" + ctx := context.Background() + + pullRequestMock := []git.GitPullRequest{ + { + PullRequestId: createIntPtr(pr_id), + SourceRefName: createStringPtr("refs/heads/feature-branch"), + LastMergeSourceCommit: &git.GitCommitRef{ + CommitId: createStringPtr(pr_head_sha), + }, + Labels: &[]core.WebApiTagDefinition{}, + Repository: &git.GitRepository{ + Name: createStringPtr(repoName), + }, + }, + } + + args := git.GetPullRequestsByProjectArgs{ + Project: &teamProject, + SearchCriteria: &git.GitPullRequestSearchCriteria{}, + } + + gitClientMock := azureMock.Client{} + clientFactoryMock := &AzureClientFactoryMock{mock: &mock.Mock{}} + clientFactoryMock.mock.On("GetClient", mock.Anything).Return(&gitClientMock, nil) + gitClientMock.On("GetPullRequestsByProject", ctx, args).Return(&pullRequestMock, nil) + + provider := AzureDevOpsService{ + clientFactory: clientFactoryMock, + project: teamProject, + repo: repoName, + labels: nil, + } + + list, err := provider.List(ctx) + assert.NoError(t, err) + assert.Equal(t, 1, len(list)) + assert.Equal(t, "feature-branch", list[0].Branch) + assert.Equal(t, pr_head_sha, list[0].HeadSHA) + assert.Equal(t, pr_id, list[0].Number) +} + +func TestConvertLabes(t *testing.T) { + testCases := []struct { + name string + gotLabels *[]core.WebApiTagDefinition + expectedLabels []string + }{ + { + name: "empty labels", + gotLabels: createLabelsPtr([]core.WebApiTagDefinition{}), + expectedLabels: []string{}, + }, + { + name: "nil labels", + gotLabels: createLabelsPtr(nil), + expectedLabels: []string{}, + }, + { + name: "one label", + gotLabels: createLabelsPtr([]core.WebApiTagDefinition{ + {Name: createStringPtr("label1"), Active: createBoolPtr(true)}, + }), + expectedLabels: []string{"label1"}, + }, + { + name: "two label", + gotLabels: createLabelsPtr([]core.WebApiTagDefinition{ + {Name: createStringPtr("label1"), Active: createBoolPtr(true)}, + {Name: createStringPtr("label2"), Active: createBoolPtr(true)}, + }), + expectedLabels: []string{"label1", "label2"}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := convertLabels(tc.gotLabels) + assert.Equal(t, tc.expectedLabels, got) + }) + } +} + +func TestContainAzureDevOpsLabels(t *testing.T) { + testCases := []struct { + name string + expectedLabels []string + gotLabels []string + expectedResult bool + }{ + { + name: "empty labels", + expectedLabels: []string{}, + gotLabels: []string{}, + expectedResult: true, + }, + { + name: "no matching labels", + expectedLabels: []string{"label1", "label2"}, + gotLabels: []string{"label3", "label4"}, + expectedResult: false, + }, + { + name: "some matching labels", + expectedLabels: []string{"label1", "label2"}, + gotLabels: []string{"label1", "label3"}, + expectedResult: false, + }, + { + name: "all matching labels", + expectedLabels: []string{"label1", "label2"}, + gotLabels: []string{"label1", "label2"}, + expectedResult: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + got := containAzureDevOpsLabels(tc.expectedLabels, tc.gotLabels) + assert.Equal(t, tc.expectedResult, got) + }) + } +} + +func TestBuildURL(t *testing.T) { + testCases := []struct { + name string + url string + organization string + expected string + }{ + { + name: "Provided default URL and organization", + url: "https://dev.azure.com/", + organization: "myorganization", + expected: "https://dev.azure.com/myorganization", + }, + { + name: "Provided default URL and organization without trailing slash", + url: "https://dev.azure.com", + organization: "myorganization", + expected: "https://dev.azure.com/myorganization", + }, + { + name: "Provided no URL and organization", + url: "", + organization: "myorganization", + expected: "https://dev.azure.com/myorganization", + }, + { + name: "Provided custom URL and organization", + url: "https://azuredevops.example.com/", + organization: "myorganization", + expected: "https://azuredevops.example.com/myorganization", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := buildURL(tc.url, tc.organization) + assert.Equal(t, result, tc.expected) + }) + } +} diff --git a/applicationset/services/pull_request/bitbucket_cloud.go b/applicationset/services/pull_request/bitbucket_cloud.go new file mode 100644 index 0000000000000..5d5f8208f9b06 --- /dev/null +++ b/applicationset/services/pull_request/bitbucket_cloud.go @@ -0,0 +1,138 @@ +package pull_request + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + + "github.com/ktrysmt/go-bitbucket" +) + +type BitbucketCloudService struct { + client *bitbucket.Client + owner string + repositorySlug string +} + +type BitbucketCloudPullRequest struct { + ID int `json:"id"` + Source BitbucketCloudPullRequestSource `json:"source"` +} + +type BitbucketCloudPullRequestSource struct { + Branch BitbucketCloudPullRequestSourceBranch `json:"branch"` + Commit BitbucketCloudPullRequestSourceCommit `json:"commit"` +} + +type BitbucketCloudPullRequestSourceBranch struct { + Name string `json:"name"` +} + +type BitbucketCloudPullRequestSourceCommit struct { + Hash string `json:"hash"` +} + +type PullRequestResponse struct { + Page int32 `json:"page"` + Size int32 `json:"size"` + Pagelen int32 `json:"pagelen"` + Next string `json:"next"` + Previous string `json:"previous"` + Items []PullRequest `json:"values"` +} + +var _ PullRequestService = (*BitbucketCloudService)(nil) + +func parseUrl(uri string) (*url.URL, error) { + if uri == "" { + uri = "https://api.bitbucket.org/2.0" + } + + url, err := url.Parse(uri) + if err != nil { + return nil, err + } + + return url, nil +} + +func NewBitbucketCloudServiceBasicAuth(baseUrl, username, password, owner, repositorySlug string) (PullRequestService, error) { + url, err := parseUrl(baseUrl) + if err != nil { + return nil, fmt.Errorf("error parsing base url of %s for %s/%s: %v", baseUrl, owner, repositorySlug, err) + } + + bitbucketClient := bitbucket.NewBasicAuth(username, password) + bitbucketClient.SetApiBaseURL(*url) + + return &BitbucketCloudService{ + client: bitbucketClient, + owner: owner, + repositorySlug: repositorySlug, + }, nil +} + +func NewBitbucketCloudServiceBearerToken(baseUrl, bearerToken, owner, repositorySlug string) (PullRequestService, error) { + url, err := parseUrl(baseUrl) + if err != nil { + return nil, fmt.Errorf("error parsing base url of %s for %s/%s: %v", baseUrl, owner, repositorySlug, err) + } + + bitbucketClient := bitbucket.NewOAuthbearerToken(bearerToken) + bitbucketClient.SetApiBaseURL(*url) + + return &BitbucketCloudService{ + client: bitbucketClient, + owner: owner, + repositorySlug: repositorySlug, + }, nil +} + +func NewBitbucketCloudServiceNoAuth(baseUrl, owner, repositorySlug string) (PullRequestService, error) { + // There is currently no method to explicitly not require auth + return NewBitbucketCloudServiceBearerToken(baseUrl, "", owner, repositorySlug) +} + +func (b *BitbucketCloudService) List(_ context.Context) ([]*PullRequest, error) { + opts := &bitbucket.PullRequestsOptions{ + Owner: b.owner, + RepoSlug: b.repositorySlug, + } + + response, err := b.client.Repositories.PullRequests.Gets(opts) + if err != nil { + return nil, fmt.Errorf("error listing pull requests for %s/%s: %v", b.owner, b.repositorySlug, err) + } + + resp, ok := response.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("unknown type returned from bitbucket pull requests") + } + + repoArray, ok := resp["values"].([]interface{}) + if !ok { + return nil, fmt.Errorf("unknown type returned from response values") + } + + jsonStr, err := json.Marshal(repoArray) + if err != nil { + return nil, fmt.Errorf("error marshalling response body to json: %v", err) + } + + var pulls []BitbucketCloudPullRequest + if err := json.Unmarshal(jsonStr, &pulls); err != nil { + return nil, fmt.Errorf("error unmarshalling json to type '[]BitbucketCloudPullRequest': %v", err) + } + + pullRequests := []*PullRequest{} + for _, pull := range pulls { + pullRequests = append(pullRequests, &PullRequest{ + Number: pull.ID, + Branch: pull.Source.Branch.Name, + HeadSHA: pull.Source.Commit.Hash, + }) + } + + return pullRequests, nil +} diff --git a/applicationset/services/pull_request/bitbucket_cloud_test.go b/applicationset/services/pull_request/bitbucket_cloud_test.go new file mode 100644 index 0000000000000..2f604c1fa9ccf --- /dev/null +++ b/applicationset/services/pull_request/bitbucket_cloud_test.go @@ -0,0 +1,410 @@ +package pull_request + +import ( + "context" + "fmt" + "io" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" +) + +func defaultHandlerCloud(t *testing.T) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + var err error + switch r.RequestURI { + case "/repositories/OWNER/REPO/pullrequests/": + _, err = io.WriteString(w, `{ + "size": 1, + "pagelen": 10, + "page": 1, + "values": [ + { + "id": 101, + "source": { + "branch": { + "name": "feature/foo-bar" + }, + "commit": { + "type": "commit", + "hash": "1a8dd249c04a" + } + } + } + ] + }`) + default: + t.Fail() + } + if err != nil { + t.Fail() + } + } +} + +func TestParseUrlEmptyUrl(t *testing.T) { + url, err := parseUrl("") + bitbucketUrl, _ := url.Parse("https://api.bitbucket.org/2.0") + + assert.NoError(t, err) + assert.Equal(t, bitbucketUrl, url) +} + +func TestInvalidBaseUrlBasicAuthCloud(t *testing.T) { + _, err := NewBitbucketCloudServiceBasicAuth("http:// example.org", "user", "password", "OWNER", "REPO") + + assert.Error(t, err) +} + +func TestInvalidBaseUrlBearerTokenCloud(t *testing.T) { + _, err := NewBitbucketCloudServiceBearerToken("http:// example.org", "TOKEN", "OWNER", "REPO") + + assert.Error(t, err) +} + +func TestInvalidBaseUrlNoAuthCloud(t *testing.T) { + _, err := NewBitbucketCloudServiceNoAuth("http:// example.org", "OWNER", "REPO") + + assert.Error(t, err) +} + +func TestListPullRequestBearerTokenCloud(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "Bearer TOKEN", r.Header.Get("Authorization")) + defaultHandlerCloud(t)(w, r) + })) + defer ts.Close() + svc, err := NewBitbucketCloudServiceBearerToken(ts.URL, "TOKEN", "OWNER", "REPO") + assert.NoError(t, err) + pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{}) + assert.NoError(t, err) + assert.Equal(t, 1, len(pullRequests)) + assert.Equal(t, 101, pullRequests[0].Number) + assert.Equal(t, "feature/foo-bar", pullRequests[0].Branch) + assert.Equal(t, "1a8dd249c04a", pullRequests[0].HeadSHA) +} + +func TestListPullRequestNoAuthCloud(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Empty(t, r.Header.Get("Authorization")) + defaultHandlerCloud(t)(w, r) + })) + defer ts.Close() + svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") + assert.NoError(t, err) + pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{}) + assert.NoError(t, err) + assert.Equal(t, 1, len(pullRequests)) + assert.Equal(t, 101, pullRequests[0].Number) + assert.Equal(t, "feature/foo-bar", pullRequests[0].Branch) + assert.Equal(t, "1a8dd249c04a", pullRequests[0].HeadSHA) +} + +func TestListPullRequestBasicAuthCloud(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "Basic dXNlcjpwYXNzd29yZA==", r.Header.Get("Authorization")) + defaultHandlerCloud(t)(w, r) + })) + defer ts.Close() + svc, err := NewBitbucketCloudServiceBasicAuth(ts.URL, "user", "password", "OWNER", "REPO") + assert.NoError(t, err) + pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{}) + assert.NoError(t, err) + assert.Equal(t, 1, len(pullRequests)) + assert.Equal(t, 101, pullRequests[0].Number) + assert.Equal(t, "feature/foo-bar", pullRequests[0].Branch) + assert.Equal(t, "1a8dd249c04a", pullRequests[0].HeadSHA) +} + +func TestListPullRequestPaginationCloud(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + var err error + switch r.RequestURI { + case "/repositories/OWNER/REPO/pullrequests/": + _, err = io.WriteString(w, fmt.Sprintf(`{ + "size": 2, + "pagelen": 1, + "page": 1, + "next": "http://%s/repositories/OWNER/REPO/pullrequests/?pagelen=1&page=2", + "values": [ + { + "id": 101, + "source": { + "branch": { + "name": "feature-101" + }, + "commit": { + "type": "commit", + "hash": "1a8dd249c04a" + } + } + }, + { + "id": 102, + "source": { + "branch": { + "name": "feature-102" + }, + "commit": { + "type": "commit", + "hash": "4cf807e67a6d" + } + } + } + ] + }`, r.Host)) + case "/repositories/OWNER/REPO/pullrequests/?pagelen=1&page=2": + _, err = io.WriteString(w, fmt.Sprintf(`{ + "size": 2, + "pagelen": 1, + "page": 2, + "previous": "http://%s/repositories/OWNER/REPO/pullrequests/?pagelen=1&page=1", + "values": [ + { + "id": 103, + "source": { + "branch": { + "name": "feature-103" + }, + "commit": { + "type": "commit", + "hash": "6344d9623e3b" + } + } + } + ] + }`, r.Host)) + default: + t.Fail() + } + if err != nil { + t.Fail() + } + })) + defer ts.Close() + svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") + assert.NoError(t, err) + pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{}) + assert.NoError(t, err) + assert.Equal(t, 3, len(pullRequests)) + assert.Equal(t, PullRequest{ + Number: 101, + Branch: "feature-101", + HeadSHA: "1a8dd249c04a", + }, *pullRequests[0]) + assert.Equal(t, PullRequest{ + Number: 102, + Branch: "feature-102", + HeadSHA: "4cf807e67a6d", + }, *pullRequests[1]) + assert.Equal(t, PullRequest{ + Number: 103, + Branch: "feature-103", + HeadSHA: "6344d9623e3b", + }, *pullRequests[2]) +} + +func TestListResponseErrorCloud(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(500) + })) + defer ts.Close() + svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") + _, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{}) + assert.Error(t, err) +} + +func TestListResponseMalformedCloud(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + switch r.RequestURI { + case "/repositories/OWNER/REPO/pullrequests/": + _, err := io.WriteString(w, `[{ + "size": 1, + "pagelen": 10, + "page": 1, + "values": [{ "id": 101 }] + }]`) + if err != nil { + t.Fail() + } + default: + t.Fail() + } + })) + defer ts.Close() + svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") + _, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{}) + assert.Error(t, err) +} + +func TestListResponseMalformedValuesCloud(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + switch r.RequestURI { + case "/repositories/OWNER/REPO/pullrequests/": + _, err := io.WriteString(w, `{ + "size": 1, + "pagelen": 10, + "page": 1, + "values": { "id": 101 } + }`) + if err != nil { + t.Fail() + } + default: + t.Fail() + } + })) + defer ts.Close() + svc, _ := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") + _, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{}) + assert.Error(t, err) +} + +func TestListResponseEmptyCloud(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + switch r.RequestURI { + case "/repositories/OWNER/REPO/pullrequests/": + _, err := io.WriteString(w, `{ + "size": 1, + "pagelen": 10, + "page": 1, + "values": [] + }`) + if err != nil { + t.Fail() + } + default: + t.Fail() + } + })) + defer ts.Close() + svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") + assert.NoError(t, err) + pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{}) + assert.NoError(t, err) + assert.Empty(t, pullRequests) +} + +func TestListPullRequestBranchMatchCloud(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + var err error + switch r.RequestURI { + case "/repositories/OWNER/REPO/pullrequests/": + _, err = io.WriteString(w, fmt.Sprintf(`{ + "size": 2, + "pagelen": 1, + "page": 1, + "next": "http://%s/repositories/OWNER/REPO/pullrequests/?pagelen=1&page=2", + "values": [ + { + "id": 101, + "source": { + "branch": { + "name": "feature-101" + }, + "commit": { + "type": "commit", + "hash": "1a8dd249c04a" + } + } + }, + { + "id": 200, + "source": { + "branch": { + "name": "feature-200" + }, + "commit": { + "type": "commit", + "hash": "4cf807e67a6d" + } + } + } + ] + }`, r.Host)) + case "/repositories/OWNER/REPO/pullrequests/?pagelen=1&page=2": + _, err = io.WriteString(w, fmt.Sprintf(`{ + "size": 2, + "pagelen": 1, + "page": 2, + "previous": "http://%s/repositories/OWNER/REPO/pullrequests/?pagelen=1&page=1", + "values": [ + { + "id": 102, + "source": { + "branch": { + "name": "feature-102" + }, + "commit": { + "type": "commit", + "hash": "6344d9623e3b" + } + } + } + ] + }`, r.Host)) + default: + t.Fail() + } + if err != nil { + t.Fail() + } + })) + defer ts.Close() + regexp := `feature-1[\d]{2}` + svc, err := NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") + assert.NoError(t, err) + pullRequests, err := ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{ + { + BranchMatch: ®exp, + }, + }) + assert.NoError(t, err) + assert.Equal(t, 2, len(pullRequests)) + assert.Equal(t, PullRequest{ + Number: 101, + Branch: "feature-101", + HeadSHA: "1a8dd249c04a", + }, *pullRequests[0]) + assert.Equal(t, PullRequest{ + Number: 102, + Branch: "feature-102", + HeadSHA: "6344d9623e3b", + }, *pullRequests[1]) + + regexp = `.*2$` + svc, err = NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") + assert.NoError(t, err) + pullRequests, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{ + { + BranchMatch: ®exp, + }, + }) + assert.NoError(t, err) + assert.Equal(t, 1, len(pullRequests)) + assert.Equal(t, PullRequest{ + Number: 102, + Branch: "feature-102", + HeadSHA: "6344d9623e3b", + }, *pullRequests[0]) + + regexp = `[\d{2}` + svc, err = NewBitbucketCloudServiceNoAuth(ts.URL, "OWNER", "REPO") + assert.NoError(t, err) + _, err = ListPullRequests(context.Background(), svc, []v1alpha1.PullRequestGeneratorFilter{ + { + BranchMatch: ®exp, + }, + }) + assert.Error(t, err) +} diff --git a/applicationset/services/pull_request/bitbucket_server.go b/applicationset/services/pull_request/bitbucket_server.go index 72cd6dd7e1900..99665d163e1bc 100644 --- a/applicationset/services/pull_request/bitbucket_server.go +++ b/applicationset/services/pull_request/bitbucket_server.go @@ -66,10 +66,11 @@ func (b *BitbucketService) List(_ context.Context) ([]*PullRequest, error) { for _, pull := range pulls { pullRequests = append(pullRequests, &PullRequest{ - Number: pull.ID, - Branch: pull.FromRef.DisplayID, // ID: refs/heads/main DisplayID: main - HeadSHA: pull.FromRef.LatestCommit, // This is not defined in the official docs, but works in practice - Labels: []string{}, // Not supported by library + Number: pull.ID, + Branch: pull.FromRef.DisplayID, // ID: refs/heads/main DisplayID: main + TargetBranch: pull.ToRef.DisplayID, + HeadSHA: pull.FromRef.LatestCommit, // This is not defined in the official docs, but works in practice + Labels: []string{}, // Not supported by library }) } diff --git a/applicationset/services/pull_request/bitbucket_server_test.go b/applicationset/services/pull_request/bitbucket_server_test.go index 0204d2aefa8d4..911e3e7e0ccd0 100644 --- a/applicationset/services/pull_request/bitbucket_server_test.go +++ b/applicationset/services/pull_request/bitbucket_server_test.go @@ -24,6 +24,11 @@ func defaultHandler(t *testing.T) func(http.ResponseWriter, *http.Request) { "values": [ { "id": 101, + "toRef": { + "latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a", + "displayId": "master", + "id": "refs/heads/master" + }, "fromRef": { "id": "refs/heads/feature-ABC-123", "displayId": "feature-ABC-123", @@ -55,6 +60,7 @@ func TestListPullRequestNoAuth(t *testing.T) { assert.Equal(t, 1, len(pullRequests)) assert.Equal(t, 101, pullRequests[0].Number) assert.Equal(t, "feature-ABC-123", pullRequests[0].Branch) + assert.Equal(t, "master", pullRequests[0].TargetBranch) assert.Equal(t, "cb3cf2e4d1517c83e720d2585b9402dbef71f992", pullRequests[0].HeadSHA) } @@ -71,6 +77,11 @@ func TestListPullRequestPagination(t *testing.T) { "values": [ { "id": 101, + "toRef": { + "latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a", + "displayId": "master", + "id": "refs/heads/master" + }, "fromRef": { "id": "refs/heads/feature-101", "displayId": "feature-101", @@ -79,6 +90,11 @@ func TestListPullRequestPagination(t *testing.T) { }, { "id": 102, + "toRef": { + "latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a", + "displayId": "branch", + "id": "refs/heads/branch" + }, "fromRef": { "id": "refs/heads/feature-102", "displayId": "feature-102", @@ -96,6 +112,11 @@ func TestListPullRequestPagination(t *testing.T) { "values": [ { "id": 200, + "toRef": { + "latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a", + "displayId": "master", + "id": "refs/heads/master" + }, "fromRef": { "id": "refs/heads/feature-200", "displayId": "feature-200", @@ -119,22 +140,25 @@ func TestListPullRequestPagination(t *testing.T) { assert.NoError(t, err) assert.Equal(t, 3, len(pullRequests)) assert.Equal(t, PullRequest{ - Number: 101, - Branch: "feature-101", - HeadSHA: "ab3cf2e4d1517c83e720d2585b9402dbef71f992", - Labels: []string{}, + Number: 101, + Branch: "feature-101", + TargetBranch: "master", + HeadSHA: "ab3cf2e4d1517c83e720d2585b9402dbef71f992", + Labels: []string{}, }, *pullRequests[0]) assert.Equal(t, PullRequest{ - Number: 102, - Branch: "feature-102", - HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992", - Labels: []string{}, + Number: 102, + Branch: "feature-102", + TargetBranch: "branch", + HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992", + Labels: []string{}, }, *pullRequests[1]) assert.Equal(t, PullRequest{ - Number: 200, - Branch: "feature-200", - HeadSHA: "cb3cf2e4d1517c83e720d2585b9402dbef71f992", - Labels: []string{}, + Number: 200, + Branch: "feature-200", + TargetBranch: "master", + HeadSHA: "cb3cf2e4d1517c83e720d2585b9402dbef71f992", + Labels: []string{}, }, *pullRequests[2]) } @@ -158,7 +182,7 @@ func TestListPullRequestBasicAuth(t *testing.T) { func TestListResponseError(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(500) + w.WriteHeader(http.StatusInternalServerError) })) defer ts.Close() svc, _ := NewBitbucketServiceNoAuth(context.Background(), ts.URL, "PROJECT", "REPO") @@ -231,6 +255,11 @@ func TestListPullRequestBranchMatch(t *testing.T) { "values": [ { "id": 101, + "toRef": { + "latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a", + "displayId": "master", + "id": "refs/heads/master" + }, "fromRef": { "id": "refs/heads/feature-101", "displayId": "feature-101", @@ -239,6 +268,11 @@ func TestListPullRequestBranchMatch(t *testing.T) { }, { "id": 102, + "toRef": { + "latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a", + "displayId": "branch", + "id": "refs/heads/branch" + }, "fromRef": { "id": "refs/heads/feature-102", "displayId": "feature-102", @@ -256,6 +290,11 @@ func TestListPullRequestBranchMatch(t *testing.T) { "values": [ { "id": 200, + "toRef": { + "latestCommit": "5b766e3564a3453808f3cd3dd3f2e5fad8ef0e7a", + "displayId": "master", + "id": "refs/heads/master" + }, "fromRef": { "id": "refs/heads/feature-200", "displayId": "feature-200", @@ -284,16 +323,18 @@ func TestListPullRequestBranchMatch(t *testing.T) { assert.NoError(t, err) assert.Equal(t, 2, len(pullRequests)) assert.Equal(t, PullRequest{ - Number: 101, - Branch: "feature-101", - HeadSHA: "ab3cf2e4d1517c83e720d2585b9402dbef71f992", - Labels: []string{}, + Number: 101, + Branch: "feature-101", + TargetBranch: "master", + HeadSHA: "ab3cf2e4d1517c83e720d2585b9402dbef71f992", + Labels: []string{}, }, *pullRequests[0]) assert.Equal(t, PullRequest{ - Number: 102, - Branch: "feature-102", - HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992", - Labels: []string{}, + Number: 102, + Branch: "feature-102", + TargetBranch: "branch", + HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992", + Labels: []string{}, }, *pullRequests[1]) regexp = `.*2$` @@ -307,10 +348,11 @@ func TestListPullRequestBranchMatch(t *testing.T) { assert.NoError(t, err) assert.Equal(t, 1, len(pullRequests)) assert.Equal(t, PullRequest{ - Number: 102, - Branch: "feature-102", - HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992", - Labels: []string{}, + Number: 102, + Branch: "feature-102", + TargetBranch: "branch", + HeadSHA: "bb3cf2e4d1517c83e720d2585b9402dbef71f992", + Labels: []string{}, }, *pullRequests[0]) regexp = `[\d{2}` diff --git a/applicationset/services/pull_request/gitea.go b/applicationset/services/pull_request/gitea.go index f913fb35580f5..ff385ff281c6d 100644 --- a/applicationset/services/pull_request/gitea.go +++ b/applicationset/services/pull_request/gitea.go @@ -26,11 +26,13 @@ func NewGiteaService(ctx context.Context, token, url, owner, repo string, insecu if insecure { cookieJar, _ := cookiejar.New(nil) + tr := http.DefaultTransport.(*http.Transport).Clone() + tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + httpClient = &http.Client{ - Jar: cookieJar, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - }} + Jar: cookieJar, + Transport: tr, + } } client, err := gitea.NewClient(url, gitea.SetToken(token), gitea.SetHTTPClient(httpClient)) if err != nil { @@ -54,10 +56,11 @@ func (g *GiteaService) List(ctx context.Context) ([]*PullRequest, error) { list := []*PullRequest{} for _, pr := range prs { list = append(list, &PullRequest{ - Number: int(pr.Index), - Branch: pr.Head.Ref, - HeadSHA: pr.Head.Sha, - Labels: getGiteaPRLabelNames(pr.Labels), + Number: int(pr.Index), + Branch: pr.Head.Ref, + TargetBranch: pr.Base.Ref, + HeadSHA: pr.Head.Sha, + Labels: getGiteaPRLabelNames(pr.Labels), }) } return list, nil diff --git a/applicationset/services/pull_request/gitea_test.go b/applicationset/services/pull_request/gitea_test.go index 9d5ff25748234..125c8ee481b3a 100644 --- a/applicationset/services/pull_request/gitea_test.go +++ b/applicationset/services/pull_request/gitea_test.go @@ -256,6 +256,7 @@ func TestGiteaList(t *testing.T) { assert.Equal(t, len(prs), 1) assert.Equal(t, prs[0].Number, 1) assert.Equal(t, prs[0].Branch, "test") + assert.Equal(t, prs[0].TargetBranch, "main") assert.Equal(t, prs[0].HeadSHA, "7bbaf62d92ddfafd9cc8b340c619abaec32bc09f") } @@ -268,9 +269,9 @@ func TestGetGiteaPRLabelNames(t *testing.T) { { Name: "PR has labels", PullLabels: []*gitea.Label{ - &gitea.Label{Name: "label1"}, - &gitea.Label{Name: "label2"}, - &gitea.Label{Name: "label3"}, + {Name: "label1"}, + {Name: "label2"}, + {Name: "label3"}, }, ExpectedResult: []string{"label1", "label2", "label3"}, }, diff --git a/applicationset/services/pull_request/github.go b/applicationset/services/pull_request/github.go index a40588ec3d367..7c801e7370f53 100644 --- a/applicationset/services/pull_request/github.go +++ b/applicationset/services/pull_request/github.go @@ -65,10 +65,11 @@ func (g *GithubService) List(ctx context.Context) ([]*PullRequest, error) { continue } pullRequests = append(pullRequests, &PullRequest{ - Number: *pull.Number, - Branch: *pull.Head.Ref, - HeadSHA: *pull.Head.SHA, - Labels: getGithubPRLabelNames(pull.Labels), + Number: *pull.Number, + Branch: *pull.Head.Ref, + TargetBranch: *pull.Base.Ref, + HeadSHA: *pull.Head.SHA, + Labels: getGithubPRLabelNames(pull.Labels), }) } if resp.NextPage == 0 { diff --git a/applicationset/services/pull_request/github_test.go b/applicationset/services/pull_request/github_test.go index 4c89404c09a6a..c47031acb7e31 100644 --- a/applicationset/services/pull_request/github_test.go +++ b/applicationset/services/pull_request/github_test.go @@ -22,9 +22,9 @@ func TestContainLabels(t *testing.T) { Name: "Match labels", Labels: []string{"label1", "label2"}, PullLabels: []*github.Label{ - &github.Label{Name: toPtr("label1")}, - &github.Label{Name: toPtr("label2")}, - &github.Label{Name: toPtr("label3")}, + {Name: toPtr("label1")}, + {Name: toPtr("label2")}, + {Name: toPtr("label3")}, }, Expect: true, }, @@ -32,9 +32,9 @@ func TestContainLabels(t *testing.T) { Name: "Not match labels", Labels: []string{"label1", "label4"}, PullLabels: []*github.Label{ - &github.Label{Name: toPtr("label1")}, - &github.Label{Name: toPtr("label2")}, - &github.Label{Name: toPtr("label3")}, + {Name: toPtr("label1")}, + {Name: toPtr("label2")}, + {Name: toPtr("label3")}, }, Expect: false, }, @@ -42,9 +42,9 @@ func TestContainLabels(t *testing.T) { Name: "No specify", Labels: []string{}, PullLabels: []*github.Label{ - &github.Label{Name: toPtr("label1")}, - &github.Label{Name: toPtr("label2")}, - &github.Label{Name: toPtr("label3")}, + {Name: toPtr("label1")}, + {Name: toPtr("label2")}, + {Name: toPtr("label3")}, }, Expect: true, }, @@ -68,9 +68,9 @@ func TestGetGitHubPRLabelNames(t *testing.T) { { Name: "PR has labels", PullLabels: []*github.Label{ - &github.Label{Name: toPtr("label1")}, - &github.Label{Name: toPtr("label2")}, - &github.Label{Name: toPtr("label3")}, + {Name: toPtr("label1")}, + {Name: toPtr("label2")}, + {Name: toPtr("label3")}, }, ExpectedResult: []string{"label1", "label2", "label3"}, }, diff --git a/applicationset/services/pull_request/gitlab.go b/applicationset/services/pull_request/gitlab.go index 39f6250aae0e8..04a4f3464f6f0 100644 --- a/applicationset/services/pull_request/gitlab.go +++ b/applicationset/services/pull_request/gitlab.go @@ -3,8 +3,11 @@ package pull_request import ( "context" "fmt" + "net/http" "os" + "github.com/argoproj/argo-cd/v2/applicationset/utils" + "github.com/hashicorp/go-retryablehttp" gitlab "github.com/xanzy/go-gitlab" ) @@ -17,7 +20,7 @@ type GitLabService struct { var _ PullRequestService = (*GitLabService)(nil) -func NewGitLabService(ctx context.Context, token, url, project string, labels []string, pullRequestState string) (PullRequestService, error) { +func NewGitLabService(ctx context.Context, token, url, project string, labels []string, pullRequestState string, scmRootCAPath string, insecure bool) (PullRequestService, error) { var clientOptionFns []gitlab.ClientOptionFunc // Set a custom Gitlab base URL if one is provided @@ -29,6 +32,14 @@ func NewGitLabService(ctx context.Context, token, url, project string, labels [] token = os.Getenv("GITLAB_TOKEN") } + tr := http.DefaultTransport.(*http.Transport).Clone() + tr.TLSClientConfig = utils.GetTlsConfig(scmRootCAPath, insecure) + + retryClient := retryablehttp.NewClient() + retryClient.HTTPClient.Transport = tr + + clientOptionFns = append(clientOptionFns, gitlab.WithHTTPClient(retryClient.HTTPClient)) + client, err := gitlab.NewClient(token, clientOptionFns...) if err != nil { return nil, fmt.Errorf("error creating Gitlab client: %v", err) @@ -69,10 +80,11 @@ func (g *GitLabService) List(ctx context.Context) ([]*PullRequest, error) { } for _, mr := range mrs { pullRequests = append(pullRequests, &PullRequest{ - Number: mr.IID, - Branch: mr.SourceBranch, - HeadSHA: mr.SHA, - Labels: mr.Labels, + Number: mr.IID, + Branch: mr.SourceBranch, + TargetBranch: mr.TargetBranch, + HeadSHA: mr.SHA, + Labels: mr.Labels, }) } if resp.NextPage == 0 { diff --git a/applicationset/services/pull_request/gitlab_test.go b/applicationset/services/pull_request/gitlab_test.go index 7c42e6f9f9269..59c476fcd713a 100644 --- a/applicationset/services/pull_request/gitlab_test.go +++ b/applicationset/services/pull_request/gitlab_test.go @@ -34,7 +34,7 @@ func TestGitLabServiceCustomBaseURL(t *testing.T) { writeMRListResponse(t, w) }) - svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", nil, "") + svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", nil, "", "", false) assert.NoError(t, err) _, err = svc.List(context.Background()) @@ -53,7 +53,7 @@ func TestGitLabServiceToken(t *testing.T) { writeMRListResponse(t, w) }) - svc, err := NewGitLabService(context.Background(), "token-123", server.URL, "278964", nil, "") + svc, err := NewGitLabService(context.Background(), "token-123", server.URL, "278964", nil, "", "", false) assert.NoError(t, err) _, err = svc.List(context.Background()) @@ -72,7 +72,7 @@ func TestList(t *testing.T) { writeMRListResponse(t, w) }) - svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{}, "") + svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{}, "", "", false) assert.NoError(t, err) prs, err := svc.List(context.Background()) @@ -80,6 +80,7 @@ func TestList(t *testing.T) { assert.Len(t, prs, 1) assert.Equal(t, prs[0].Number, 15442) assert.Equal(t, prs[0].Branch, "use-structured-logging-for-db-load-balancer") + assert.Equal(t, prs[0].TargetBranch, "master") assert.Equal(t, prs[0].HeadSHA, "2fc4e8b972ff3208ec63b6143e34ad67ff343ad7") } @@ -95,7 +96,7 @@ func TestListWithLabels(t *testing.T) { writeMRListResponse(t, w) }) - svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{"feature", "ready"}, "") + svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{"feature", "ready"}, "", "", false) assert.NoError(t, err) _, err = svc.List(context.Background()) @@ -114,7 +115,7 @@ func TestListWithState(t *testing.T) { writeMRListResponse(t, w) }) - svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{}, "opened") + svc, err := NewGitLabService(context.Background(), "", server.URL, "278964", []string{}, "opened", "", false) assert.NoError(t, err) _, err = svc.List(context.Background()) diff --git a/applicationset/services/pull_request/interface.go b/applicationset/services/pull_request/interface.go index f81dc35e41435..0015cfe5eafa6 100644 --- a/applicationset/services/pull_request/interface.go +++ b/applicationset/services/pull_request/interface.go @@ -10,6 +10,8 @@ type PullRequest struct { Number int // Branch is the name of the branch from which the pull request originated. Branch string + // TargetBranch is the name of the target branch of the pull request. + TargetBranch string // HeadSHA is the SHA of the HEAD from which the pull request originated. HeadSHA string // Labels of the pull request. @@ -22,5 +24,6 @@ type PullRequestService interface { } type Filter struct { - BranchMatch *regexp.Regexp + BranchMatch *regexp.Regexp + TargetBranchMatch *regexp.Regexp } diff --git a/applicationset/services/pull_request/utils.go b/applicationset/services/pull_request/utils.go index c7970170a7d64..50d4e5a3c0098 100644 --- a/applicationset/services/pull_request/utils.go +++ b/applicationset/services/pull_request/utils.go @@ -19,6 +19,12 @@ func compileFilters(filters []argoprojiov1alpha1.PullRequestGeneratorFilter) ([] return nil, fmt.Errorf("error compiling BranchMatch regexp %q: %v", *filter.BranchMatch, err) } } + if filter.TargetBranchMatch != nil { + outFilter.TargetBranchMatch, err = regexp.Compile(*filter.TargetBranchMatch) + if err != nil { + return nil, fmt.Errorf("error compiling TargetBranchMatch regexp %q: %v", *filter.TargetBranchMatch, err) + } + } outFilters = append(outFilters, outFilter) } return outFilters, nil @@ -28,6 +34,9 @@ func matchFilter(pullRequest *PullRequest, filter *Filter) bool { if filter.BranchMatch != nil && !filter.BranchMatch.MatchString(pullRequest.Branch) { return false } + if filter.TargetBranchMatch != nil && !filter.TargetBranchMatch.MatchString(pullRequest.TargetBranch) { + return false + } return true } diff --git a/applicationset/services/pull_request/utils_test.go b/applicationset/services/pull_request/utils_test.go index eb92e5fad866f..3f813127edab7 100644 --- a/applicationset/services/pull_request/utils_test.go +++ b/applicationset/services/pull_request/utils_test.go @@ -16,9 +16,10 @@ func TestFilterBranchMatchBadRegexp(t *testing.T) { context.Background(), []*PullRequest{ { - Number: 1, - Branch: "branch1", - HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958", + Number: 1, + Branch: "branch1", + TargetBranch: "master", + HeadSHA: "089d92cbf9ff857a39e6feccd32798ca700fb958", }, }, nil, @@ -37,24 +38,28 @@ func TestFilterBranchMatch(t *testing.T) { context.Background(), []*PullRequest{ { - Number: 1, - Branch: "one", - HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958", + Number: 1, + Branch: "one", + TargetBranch: "master", + HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958", }, { - Number: 2, - Branch: "two", - HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958", + Number: 2, + Branch: "two", + TargetBranch: "master", + HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958", }, { - Number: 3, - Branch: "three", - HeadSHA: "389d92cbf9ff857a39e6feccd32798ca700fb958", + Number: 3, + Branch: "three", + TargetBranch: "master", + HeadSHA: "389d92cbf9ff857a39e6feccd32798ca700fb958", }, { - Number: 4, - Branch: "four", - HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958", + Number: 4, + Branch: "four", + TargetBranch: "master", + HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958", }, }, nil, @@ -70,29 +75,75 @@ func TestFilterBranchMatch(t *testing.T) { assert.Equal(t, "two", pullRequests[0].Branch) } +func TestFilterTargetBranchMatch(t *testing.T) { + provider, _ := NewFakeService( + context.Background(), + []*PullRequest{ + { + Number: 1, + Branch: "one", + TargetBranch: "master", + HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958", + }, + { + Number: 2, + Branch: "two", + TargetBranch: "branch1", + HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958", + }, + { + Number: 3, + Branch: "three", + TargetBranch: "branch2", + HeadSHA: "389d92cbf9ff857a39e6feccd32798ca700fb958", + }, + { + Number: 4, + Branch: "four", + TargetBranch: "branch3", + HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958", + }, + }, + nil, + ) + filters := []argoprojiov1alpha1.PullRequestGeneratorFilter{ + { + TargetBranchMatch: strp("1"), + }, + } + pullRequests, err := ListPullRequests(context.Background(), provider, filters) + assert.NoError(t, err) + assert.Len(t, pullRequests, 1) + assert.Equal(t, "two", pullRequests[0].Branch) +} + func TestMultiFilterOr(t *testing.T) { provider, _ := NewFakeService( context.Background(), []*PullRequest{ { - Number: 1, - Branch: "one", - HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958", + Number: 1, + Branch: "one", + TargetBranch: "master", + HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958", }, { - Number: 2, - Branch: "two", - HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958", + Number: 2, + Branch: "two", + TargetBranch: "master", + HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958", }, { - Number: 3, - Branch: "three", - HeadSHA: "389d92cbf9ff857a39e6feccd32798ca700fb958", + Number: 3, + Branch: "three", + TargetBranch: "master", + HeadSHA: "389d92cbf9ff857a39e6feccd32798ca700fb958", }, { - Number: 4, - Branch: "four", - HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958", + Number: 4, + Branch: "four", + TargetBranch: "master", + HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958", }, }, nil, @@ -113,19 +164,69 @@ func TestMultiFilterOr(t *testing.T) { assert.Equal(t, "four", pullRequests[2].Branch) } +func TestMultiFilterOrWithTargetBranchFilter(t *testing.T) { + provider, _ := NewFakeService( + context.Background(), + []*PullRequest{ + { + Number: 1, + Branch: "one", + TargetBranch: "master", + HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958", + }, + { + Number: 2, + Branch: "two", + TargetBranch: "branch1", + HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958", + }, + { + Number: 3, + Branch: "three", + TargetBranch: "branch2", + HeadSHA: "389d92cbf9ff857a39e6feccd32798ca700fb958", + }, + { + Number: 4, + Branch: "four", + TargetBranch: "branch3", + HeadSHA: "489d92cbf9ff857a39e6feccd32798ca700fb958", + }, + }, + nil, + ) + filters := []argoprojiov1alpha1.PullRequestGeneratorFilter{ + { + BranchMatch: strp("w"), + TargetBranchMatch: strp("1"), + }, + { + BranchMatch: strp("r"), + TargetBranchMatch: strp("3"), + }, + } + pullRequests, err := ListPullRequests(context.Background(), provider, filters) + assert.NoError(t, err) + assert.Len(t, pullRequests, 2) + assert.Equal(t, "two", pullRequests[0].Branch) + assert.Equal(t, "four", pullRequests[1].Branch) +} + func TestNoFilters(t *testing.T) { provider, _ := NewFakeService( context.Background(), []*PullRequest{ { - Number: 1, - Branch: "one", - HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958", + Number: 1, + Branch: "one", + TargetBranch: "master", + HeadSHA: "189d92cbf9ff857a39e6feccd32798ca700fb958", }, { - Number: 2, - Branch: "two", - HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958", + Number: 2, + Branch: "two", + TargetBranch: "master", + HeadSHA: "289d92cbf9ff857a39e6feccd32798ca700fb958", }, }, nil, diff --git a/applicationset/services/repo_service.go b/applicationset/services/repo_service.go index 571f497433de8..64fedc34390b8 100644 --- a/applicationset/services/repo_service.go +++ b/applicationset/services/repo_service.go @@ -3,151 +3,100 @@ package services import ( "context" "fmt" - "os" - "path/filepath" - "strings" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/v2/reposerver/apiclient" "github.com/argoproj/argo-cd/v2/util/db" "github.com/argoproj/argo-cd/v2/util/git" + "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 more easy to test the functionality the git generator uses +// Using a lean interface makes it easier to test the functionality of the git generator type RepositoryDB interface { GetRepository(ctx context.Context, url string) (*v1alpha1.Repository, error) } type argoCDService struct { - repositoriesDB RepositoryDB - storecreds git.CredsStore - submoduleEnabled bool + repositoriesDB RepositoryDB + storecreds git.CredsStore + submoduleEnabled bool + repoServerClientSet apiclient.Clientset + 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, gitCredStore git.CredsStore, submoduleEnabled bool) Repos { - +func NewArgoCDService(db db.ArgoDB, submoduleEnabled bool, repoClientset apiclient.Clientset, newFileGlobbingEnabled bool) (Repos, error) { return &argoCDService{ - repositoriesDB: db.(RepositoryDB), - storecreds: gitCredStore, - submoduleEnabled: submoduleEnabled, - } + repositoriesDB: db.(RepositoryDB), + submoduleEnabled: submoduleEnabled, + repoServerClientSet: repoClientset, + newFileGlobbingEnabled: newFileGlobbingEnabled, + }, 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) + return nil, fmt.Errorf("error in GetRepository: %w", err) } - gitRepoClient, err := git.NewClient(repo.Repo, repo.GetGitCreds(a.storecreds), repo.IsInsecure(), repo.IsLFSEnabled(), repo.Proxy) - - if err != nil { - return nil, err + fileRequest := &apiclient.GitFilesRequest{ + Repo: repo, + SubmoduleEnabled: a.submoduleEnabled, + Revision: revision, + Path: pattern, + NewGitFileGlobbingEnabled: a.newFileGlobbingEnabled, + NoRevisionCache: noRevisionCache, } - - err = checkoutRepo(gitRepoClient, revision, a.submoduleEnabled) + closer, client, err := a.repoServerClientSet.NewRepoServerClient() if err != nil { - return nil, err + return nil, fmt.Errorf("error initialising new repo server client: %w", err) } + defer io.Close(closer) - paths, err := gitRepoClient.LsFiles(pattern) + fileResponse, err := client.GetGitFiles(ctx, fileRequest) if err != nil { - return nil, fmt.Errorf("Error during listing files of local repo: %w", err) - } - - res := map[string][]byte{} - for _, filePath := range paths { - bytes, err := os.ReadFile(filepath.Join(gitRepoClient.Root(), filePath)) - if err != nil { - return nil, err - } - res[filePath] = bytes + return nil, fmt.Errorf("error retrieving Git files: %w", err) } - - return res, nil + 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) + return nil, fmt.Errorf("error in GetRepository: %w", err) } - gitRepoClient, err := git.NewClient(repo.Repo, repo.GetGitCreds(a.storecreds), repo.IsInsecure(), repo.IsLFSEnabled(), repo.Proxy) - if err != nil { - return nil, fmt.Errorf("error creating a new git client: %w", err) + dirRequest := &apiclient.GitDirectoriesRequest{ + Repo: repo, + SubmoduleEnabled: a.submoduleEnabled, + Revision: revision, + NoRevisionCache: noRevisionCache, } - err = checkoutRepo(gitRepoClient, revision, a.submoduleEnabled) + closer, client, err := a.repoServerClientSet.NewRepoServerClient() if err != nil { - return nil, fmt.Errorf("error while checking out repo: %w", err) + return nil, fmt.Errorf("error initialising new repo server client: %w", err) } + defer io.Close(closer) - filteredPaths := []string{} - - repoRoot := gitRepoClient.Root() - - if err := filepath.Walk(repoRoot, func(path string, info os.FileInfo, fnErr error) error { - if fnErr != nil { - return fmt.Errorf("error walking the file tree: %w", fnErr) - } - if !info.IsDir() { // Skip files: directories only - return nil - } - - fname := info.Name() - if strings.HasPrefix(fname, ".") { // Skip all folders starts with "." - return filepath.SkipDir - } - - relativePath, err := filepath.Rel(repoRoot, path) - if err != nil { - return fmt.Errorf("error constructing relative repo path: %w", err) - } - - if relativePath == "." { // Exclude '.' from results - return nil - } - - filteredPaths = append(filteredPaths, relativePath) - - return nil - }); err != nil { - return nil, err - } - - return filteredPaths, nil - -} - -func checkoutRepo(gitRepoClient git.Client, revision string, submoduleEnabled bool) error { - err := gitRepoClient.Init() + dirResponse, err := client.GetGitDirectories(ctx, dirRequest) if err != nil { - return fmt.Errorf("Error during initializing repo: %w", err) + return nil, fmt.Errorf("error retrieving Git Directories: %w", err) } + return dirResponse.GetPaths(), nil - err = gitRepoClient.Fetch(revision) - if err != nil { - return fmt.Errorf("Error during fetching repo: %w", err) - } - - commitSHA, err := gitRepoClient.LsRemote(revision) - if err != nil { - return fmt.Errorf("Error during fetching commitSHA: %w", err) - } - err = gitRepoClient.Checkout(commitSHA, submoduleEnabled) - if err != nil { - return fmt.Errorf("Error during repo checkout: %w", err) - } - return nil } diff --git a/applicationset/services/repo_service_test.go b/applicationset/services/repo_service_test.go index bc0238b2eacc7..040fe57f96958 100644 --- a/applicationset/services/repo_service_test.go +++ b/applicationset/services/repo_service_test.go @@ -3,231 +3,191 @@ package services import ( "context" "fmt" - "sort" "testing" + "github.com/argoproj/argo-cd/v2/applicationset/services/mocks" + "github.com/argoproj/argo-cd/v2/reposerver/apiclient" + repo_mocks "github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks" + db_mocks "github.com/argoproj/argo-cd/v2/util/db/mocks" + "github.com/argoproj/argo-cd/v2/util/git" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) -type ArgocdRepositoryMock struct { - mock *mock.Mock -} - -func (a ArgocdRepositoryMock) GetRepository(ctx context.Context, url string) (*v1alpha1.Repository, error) { - args := a.mock.Called(ctx, url) - - return args.Get(0).(*v1alpha1.Repository), args.Error(1) - -} - func TestGetDirectories(t *testing.T) { - // Hardcode a specific revision to changes to argocd-example-apps from regressing this test: - // Author: Alexander Matyushentsev - // Date: Sun Jan 31 09:54:53 2021 -0800 - // chore: downgrade kustomize guestbook image tag (#73) - exampleRepoRevision := "08f72e2a309beab929d9fd14626071b1a61a47f9" - - for _, c := range []struct { - name string - repoURL string - revision string - repoRes *v1alpha1.Repository - repoErr error - expected []string - expectedError error + type fields struct { + repositoriesDBFuncs []func(*mocks.RepositoryDB) + storecreds git.CredsStore + submoduleEnabled bool + repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient) + } + type args struct { + ctx context.Context + repoURL string + revision string + noRevisionCache bool + } + tests := []struct { + name string + fields fields + args args + want []string + wantErr assert.ErrorAssertionFunc }{ - { - name: "All child folders should be returned", - repoURL: "https://github.com/argoproj/argocd-example-apps/", - revision: exampleRepoRevision, - repoRes: &v1alpha1.Repository{ - Repo: "https://github.com/argoproj/argocd-example-apps/", + {name: "ErrorGettingRepos", fields: fields{ + repositoriesDBFuncs: []func(*mocks.RepositoryDB){ + func(db *mocks.RepositoryDB) { + db.On("GetRepository", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("unable to get repos")) + }, }, - repoErr: nil, - expected: []string{"apps", "apps/templates", "blue-green", "blue-green/templates", "guestbook", "helm-dependency", - "helm-guestbook", "helm-guestbook/templates", "helm-hooks", "jsonnet-guestbook", "jsonnet-guestbook-tla", - "ksonnet-guestbook", "ksonnet-guestbook/components", "ksonnet-guestbook/environments", "ksonnet-guestbook/environments/default", - "ksonnet-guestbook/environments/dev", "ksonnet-guestbook/environments/prod", "kustomize-guestbook", "plugins", "plugins/kasane", - "plugins/kustomized-helm", "plugins/kustomized-helm/overlays", "pre-post-sync", "sock-shop", "sock-shop/base", "sync-waves"}, - }, - { - name: "If GetRepository returns an error, it should pass back to caller", - repoURL: "https://github.com/argoproj/argocd-example-apps/", - revision: exampleRepoRevision, - repoRes: &v1alpha1.Repository{ - Repo: "https://github.com/argoproj/argocd-example-apps/", + }, args: args{}, want: nil, wantErr: assert.Error}, + {name: "ErrorGettingDirs", fields: fields{ + repositoriesDBFuncs: []func(*mocks.RepositoryDB){ + func(db *mocks.RepositoryDB) { + db.On("GetRepository", mock.Anything, mock.Anything).Return(&v1alpha1.Repository{}, nil) + }, }, - repoErr: fmt.Errorf("Simulated error from GetRepository"), - expected: nil, - expectedError: fmt.Errorf("Error in GetRepository: Simulated error from GetRepository"), - }, - { - name: "Test against repository containing no directories", - // Here I picked an arbitrary repository in argoproj-labs, with a commit containing no folders. - repoURL: "https://github.com/argoproj-labs/argo-workflows-operator/", - revision: "5f50933a576833b73b7a172909d8545a108685f4", - repoRes: &v1alpha1.Repository{ - Repo: "https://github.com/argoproj-labs/argo-workflows-operator/", + repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){ + func(client *repo_mocks.RepoServerServiceClient) { + client.On("GetGitDirectories", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("unable to get dirs")) + }, }, - repoErr: nil, - expected: []string{}, - }, - } { - cc := c - t.Run(cc.name, func(t *testing.T) { - argocdRepositoryMock := ArgocdRepositoryMock{mock: &mock.Mock{}} - - argocdRepositoryMock.mock.On("GetRepository", mock.Anything, cc.repoURL).Return(cc.repoRes, cc.repoErr) - - argocd := argoCDService{ - repositoriesDB: argocdRepositoryMock, + }, args: args{}, want: nil, wantErr: assert.Error}, + {name: "HappyCase", fields: fields{ + repositoriesDBFuncs: []func(*mocks.RepositoryDB){ + func(db *mocks.RepositoryDB) { + db.On("GetRepository", mock.Anything, mock.Anything).Return(&v1alpha1.Repository{}, nil) + }, + }, + repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){ + func(client *repo_mocks.RepoServerServiceClient) { + client.On("GetGitDirectories", mock.Anything, mock.Anything).Return(&apiclient.GitDirectoriesResponse{ + Paths: []string{"foo", "foo/bar", "bar/foo"}, + }, nil) + }, + }, + }, args: args{}, want: []string{"foo", "foo/bar", "bar/foo"}, wantErr: assert.NoError}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockDb := &mocks.RepositoryDB{} + mockRepoClient := &repo_mocks.RepoServerServiceClient{} + // decorate the mocks + for i := range tt.fields.repositoriesDBFuncs { + tt.fields.repositoriesDBFuncs[i](mockDb) + } + for i := range tt.fields.repoServerClientFuncs { + tt.fields.repoServerClientFuncs[i](mockRepoClient) } - got, err := argocd.GetDirectories(context.TODO(), cc.repoURL, cc.revision) - - if cc.expectedError != nil { - assert.EqualError(t, err, cc.expectedError.Error()) - } else { - sort.Strings(got) - sort.Strings(cc.expected) - - assert.Equal(t, got, cc.expected) - assert.NoError(t, err) + a := &argoCDService{ + repositoriesDB: mockDb, + storecreds: tt.fields.storecreds, + submoduleEnabled: tt.fields.submoduleEnabled, + repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient}, + } + 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, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.noRevisionCache) }) } } func TestGetFiles(t *testing.T) { - - // Hardcode a specific commit, so that changes to argoproj/argocd-example-apps/ don't break our tests - // "chore: downgrade kustomize guestbook image tag (#73)" - commitID := "08f72e2a309beab929d9fd14626071b1a61a47f9" - + type fields struct { + repositoriesDBFuncs []func(*mocks.RepositoryDB) + storecreds git.CredsStore + submoduleEnabled bool + repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient) + } + type args struct { + ctx context.Context + repoURL string + revision string + pattern string + noRevisionCache bool + } tests := []struct { - name string - repoURL string - revision string - pattern string - repoRes *v1alpha1.Repository - repoErr error - - expectSubsetOfPaths []string - doesNotContainPaths []string - expectedError error + name string + fields fields + args args + want map[string][]byte + wantErr assert.ErrorAssertionFunc }{ - { - name: "pull a specific revision of example apps and verify the list is expected", - repoRes: &v1alpha1.Repository{ - Insecure: true, - InsecureIgnoreHostKey: true, - Repo: "https://github.com/argoproj/argocd-example-apps/", + {name: "ErrorGettingRepos", fields: fields{ + repositoriesDBFuncs: []func(*mocks.RepositoryDB){ + func(db *mocks.RepositoryDB) { + db.On("GetRepository", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("unable to get repos")) + }, }, - repoURL: "https://github.com/argoproj/argocd-example-apps/", - revision: commitID, - pattern: "*", - expectSubsetOfPaths: []string{ - "apps/Chart.yaml", - "apps/templates/helm-guestbook.yaml", - "apps/templates/helm-hooks.yaml", - "apps/templates/kustomize-guestbook.yaml", - "apps/templates/namespaces.yaml", - "apps/templates/sync-waves.yaml", - "apps/values.yaml", - "blue-green/.helmignore", - "blue-green/Chart.yaml", - "blue-green/README.md", - "blue-green/templates/NOTES.txt", - "blue-green/templates/rollout.yaml", - "blue-green/templates/services.yaml", - "blue-green/values.yaml", - "guestbook/guestbook-ui-deployment.yaml", - "guestbook/guestbook-ui-svc.yaml", - "kustomize-guestbook/guestbook-ui-deployment.yaml", - "kustomize-guestbook/guestbook-ui-svc.yaml", - "kustomize-guestbook/kustomization.yaml", + }, args: args{}, want: nil, wantErr: assert.Error}, + {name: "ErrorGettingFiles", fields: fields{ + repositoriesDBFuncs: []func(*mocks.RepositoryDB){ + func(db *mocks.RepositoryDB) { + db.On("GetRepository", mock.Anything, mock.Anything).Return(&v1alpha1.Repository{}, nil) + }, }, - }, - { - name: "pull an invalid revision, and confirm an error is returned", - repoRes: &v1alpha1.Repository{ - Insecure: true, - InsecureIgnoreHostKey: true, - Repo: "https://github.com/argoproj/argocd-example-apps/", + repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){ + func(client *repo_mocks.RepoServerServiceClient) { + client.On("GetGitFiles", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("unable to get files")) + }, }, - repoURL: "https://github.com/argoproj/argocd-example-apps/", - revision: "this-tag-does-not-exist", - pattern: "*", - expectSubsetOfPaths: []string{}, - expectedError: fmt.Errorf("Error during fetching repo: `git fetch origin this-tag-does-not-exist --tags --force --prune` failed exit status 128: fatal: couldn't find remote ref this-tag-does-not-exist"), - }, - { - name: "pull a specific revision of example apps, and use a ** pattern", - repoRes: &v1alpha1.Repository{ - Insecure: true, - InsecureIgnoreHostKey: true, - Repo: "https://github.com/argoproj/argocd-example-apps/", + }, args: args{}, want: nil, wantErr: assert.Error}, + {name: "HappyCase", fields: fields{ + repositoriesDBFuncs: []func(*mocks.RepositoryDB){ + func(db *mocks.RepositoryDB) { + db.On("GetRepository", mock.Anything, mock.Anything).Return(&v1alpha1.Repository{}, nil) + }, }, - repoURL: "https://github.com/argoproj/argocd-example-apps/", - revision: commitID, - pattern: "**/*.yaml", - expectSubsetOfPaths: []string{ - "apps/Chart.yaml", - "apps/templates/helm-guestbook.yaml", - "apps/templates/helm-hooks.yaml", - "apps/templates/kustomize-guestbook.yaml", - "apps/templates/namespaces.yaml", - "apps/templates/sync-waves.yaml", - "apps/values.yaml", - "blue-green/templates/rollout.yaml", - "blue-green/templates/services.yaml", - "blue-green/values.yaml", - "guestbook/guestbook-ui-deployment.yaml", - "guestbook/guestbook-ui-svc.yaml", - "kustomize-guestbook/guestbook-ui-deployment.yaml", - "kustomize-guestbook/guestbook-ui-svc.yaml", - "kustomize-guestbook/kustomization.yaml", + repoServerClientFuncs: []func(*repo_mocks.RepoServerServiceClient){ + func(client *repo_mocks.RepoServerServiceClient) { + client.On("GetGitFiles", mock.Anything, mock.Anything).Return(&apiclient.GitFilesResponse{ + Map: map[string][]byte{ + "foo.json": []byte("hello: world!"), + "bar.yaml": []byte("yay: appsets"), + }, + }, nil) + }, }, - doesNotContainPaths: []string{ - "blue-green/.helmignore", - "blue-green/README.md", - "blue-green/templates/NOTES.txt", - }, - }, + }, args: args{}, want: map[string][]byte{ + "foo.json": []byte("hello: world!"), + "bar.yaml": []byte("yay: appsets"), + }, wantErr: assert.NoError}, } - - for _, cc := range tests { - - // Get all the paths for a repository, and confirm that the expected subset of paths is found (or the expected error is returned) - t.Run(cc.name, func(t *testing.T) { - argocdRepositoryMock := ArgocdRepositoryMock{mock: &mock.Mock{}} - - argocdRepositoryMock.mock.On("GetRepository", mock.Anything, cc.repoURL).Return(cc.repoRes, cc.repoErr) - - argocd := argoCDService{ - repositoriesDB: argocdRepositoryMock, + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockDb := &mocks.RepositoryDB{} + mockRepoClient := &repo_mocks.RepoServerServiceClient{} + // decorate the mocks + for i := range tt.fields.repositoriesDBFuncs { + tt.fields.repositoriesDBFuncs[i](mockDb) + } + for i := range tt.fields.repoServerClientFuncs { + tt.fields.repoServerClientFuncs[i](mockRepoClient) } - getPathsRes, err := argocd.GetFiles(context.Background(), cc.repoURL, cc.revision, cc.pattern) - - if cc.expectedError == nil { - - assert.NoError(t, err) - for _, path := range cc.expectSubsetOfPaths { - assert.Contains(t, getPathsRes, path, "Unable to locate path: %s", path) - } - - for _, shouldNotContain := range cc.doesNotContainPaths { - assert.NotContains(t, getPathsRes, shouldNotContain, "GetPaths should not contain %s", shouldNotContain) - } - - } else { - assert.EqualError(t, err, cc.expectedError.Error()) + a := &argoCDService{ + repositoriesDB: mockDb, + storecreds: tt.fields.storecreds, + 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, 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, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, tt.args.noRevisionCache) }) } } + +func TestNewArgoCDService(t *testing.T) { + service, err := NewArgoCDService(&db_mocks.ArgoDB{}, false, &repo_mocks.Clientset{}, false) + assert.NoError(t, err, err) + assert.NotNil(t, service) +} diff --git a/applicationset/services/scm_provider/aws_codecommit.go b/applicationset/services/scm_provider/aws_codecommit.go new file mode 100644 index 0000000000000..280711271cfb0 --- /dev/null +++ b/applicationset/services/scm_provider/aws_codecommit.go @@ -0,0 +1,376 @@ +package scm_provider + +import ( + "context" + "fmt" + "github.com/aws/aws-sdk-go/aws/request" + pathpkg "path" + "path/filepath" + "strings" + + application "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/aws/credentials/stscreds" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/codecommit" + "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" + log "github.com/sirupsen/logrus" + "golang.org/x/exp/maps" + "k8s.io/utils/strings/slices" +) + +const ( + resourceTypeCodeCommitRepository = "codecommit:repository" + prefixGitUrlHttps = "https://git-codecommit." + prefixGitUrlHttpsFIPS = "https://git-codecommit-fips." +) + +// AWSCodeCommitClient is a lean facade to the codecommitiface.CodeCommitAPI +// it helps to reduce the mockery generated code. +type AWSCodeCommitClient interface { + ListRepositoriesWithContext(aws.Context, *codecommit.ListRepositoriesInput, ...request.Option) (*codecommit.ListRepositoriesOutput, error) + GetRepositoryWithContext(aws.Context, *codecommit.GetRepositoryInput, ...request.Option) (*codecommit.GetRepositoryOutput, error) + ListBranchesWithContext(aws.Context, *codecommit.ListBranchesInput, ...request.Option) (*codecommit.ListBranchesOutput, error) + GetFolderWithContext(aws.Context, *codecommit.GetFolderInput, ...request.Option) (*codecommit.GetFolderOutput, error) +} + +// AWSTaggingClient is a lean facade to the resourcegroupstaggingapiiface.ResourceGroupsTaggingAPIAPI +// it helps to reduce the mockery generated code. +type AWSTaggingClient interface { + GetResourcesWithContext(aws.Context, *resourcegroupstaggingapi.GetResourcesInput, ...request.Option) (*resourcegroupstaggingapi.GetResourcesOutput, error) +} + +type AWSCodeCommitProvider struct { + codeCommitClient AWSCodeCommitClient + taggingClient AWSTaggingClient + tagFilters []*application.TagFilter + allBranches bool +} + +func NewAWSCodeCommitProvider(ctx context.Context, tagFilters []*application.TagFilter, role string, region string, allBranches bool) (*AWSCodeCommitProvider, error) { + taggingClient, codeCommitClient, err := createAWSDiscoveryClients(ctx, role, region) + if err != nil { + return nil, err + } + return &AWSCodeCommitProvider{ + codeCommitClient: codeCommitClient, + taggingClient: taggingClient, + tagFilters: tagFilters, + allBranches: allBranches, + }, nil +} + +func (p *AWSCodeCommitProvider) ListRepos(ctx context.Context, cloneProtocol string) ([]*Repository, error) { + repos := make([]*Repository, 0) + + repoNames, err := p.listRepoNames(ctx) + if err != nil { + return nil, fmt.Errorf("failed to list codecommit repository: %w", err) + } + + for _, repoName := range repoNames { + repo, err := p.codeCommitClient.GetRepositoryWithContext(ctx, &codecommit.GetRepositoryInput{ + RepositoryName: aws.String(repoName), + }) + if err != nil { + // we don't want to skip at this point. It's a valid repo, we don't want to have flapping Application on an AWS outage. + return nil, fmt.Errorf("failed to get codecommit repository: %w", err) + } + if repo == nil || repo.RepositoryMetadata == nil { + // unlikely to happen, but just in case to protect nil pointer dereferences. + log.Warnf("codecommit returned invalid response for repository %s, skipped", repoName) + continue + } + if aws.StringValue(repo.RepositoryMetadata.DefaultBranch) == "" { + // if a codecommit repo doesn't have default branch, it's uninitialized. not going to bother with it. + log.Warnf("repository %s does not have default branch, skipped", repoName) + continue + } + var url string + switch cloneProtocol { + // default to SSH if unspecified (i.e. if ""). + case "", "ssh": + url = aws.StringValue(repo.RepositoryMetadata.CloneUrlSsh) + case "https": + url = aws.StringValue(repo.RepositoryMetadata.CloneUrlHttp) + case "https-fips": + url, err = getCodeCommitFIPSEndpoint(aws.StringValue(repo.RepositoryMetadata.CloneUrlHttp)) + if err != nil { + return nil, fmt.Errorf("https-fips is provided but repoUrl can't be transformed to FIPS endpoint: %w", err) + } + default: + return nil, fmt.Errorf("unknown clone protocol for codecommit %v", cloneProtocol) + } + repos = append(repos, &Repository{ + // there's no "organization" level at codecommit. + // we are just using AWS accountId for now. + Organization: aws.StringValue(repo.RepositoryMetadata.AccountId), + Repository: aws.StringValue(repo.RepositoryMetadata.RepositoryName), + URL: url, + Branch: aws.StringValue(repo.RepositoryMetadata.DefaultBranch), + // we could propagate repo tag keys, but without value not sure if it's any useful. + Labels: []string{}, + RepositoryId: aws.StringValue(repo.RepositoryMetadata.RepositoryId), + }) + } + + return repos, nil +} + +func (p *AWSCodeCommitProvider) RepoHasPath(ctx context.Context, repo *Repository, path string) (bool, error) { + // we use GetFolder instead of GetFile here because GetFile always downloads the full blob which has scalability problem. + // GetFolder is slightly less concerning. + + path = toAbsolutePath(path) + // shortcut: if it's root folder ('/'), we always return true. + if path == "/" { + return true, nil + } + // here we are sure it's not root folder, strip the suffix for easier comparison. + path = strings.TrimSuffix(path, "/") + + // we always get the parent folder, so we could support both submodule, file, symlink and folder cases. + parentPath := pathpkg.Dir(path) + basePath := pathpkg.Base(path) + + input := &codecommit.GetFolderInput{ + CommitSpecifier: aws.String(repo.Branch), + FolderPath: aws.String(parentPath), + RepositoryName: aws.String(repo.Repository), + } + output, err := p.codeCommitClient.GetFolderWithContext(ctx, input) + if err != nil { + if hasAwsError(err, + codecommit.ErrCodeRepositoryDoesNotExistException, + codecommit.ErrCodeCommitDoesNotExistException, + codecommit.ErrCodeFolderDoesNotExistException, + ) { + return false, nil + } + // unhandled exception, propagate out + return false, err + } + + // anything that matches. + for _, submodule := range output.SubModules { + if basePath == aws.StringValue(submodule.RelativePath) { + return true, nil + } + } + for _, subpath := range output.SubFolders { + if basePath == aws.StringValue(subpath.RelativePath) { + return true, nil + } + } + for _, subpath := range output.Files { + if basePath == aws.StringValue(subpath.RelativePath) { + return true, nil + } + } + for _, subpath := range output.SymbolicLinks { + if basePath == aws.StringValue(subpath.RelativePath) { + return true, nil + } + } + return false, nil +} + +func (p *AWSCodeCommitProvider) GetBranches(ctx context.Context, repo *Repository) ([]*Repository, error) { + repos := make([]*Repository, 0) + if !p.allBranches { + output, err := p.codeCommitClient.GetRepositoryWithContext(ctx, &codecommit.GetRepositoryInput{ + RepositoryName: aws.String(repo.Repository), + }) + if err != nil { + return nil, err + } + repos = append(repos, &Repository{ + Organization: repo.Organization, + Repository: repo.Repository, + URL: repo.URL, + Branch: aws.StringValue(output.RepositoryMetadata.DefaultBranch), + RepositoryId: repo.RepositoryId, + Labels: repo.Labels, + // getting SHA of the branch requires a separate GetBranch call. + // too expensive. for now, we just don't support it. + // SHA: "", + }) + } else { + input := &codecommit.ListBranchesInput{ + RepositoryName: aws.String(repo.Repository), + } + for { + output, err := p.codeCommitClient.ListBranchesWithContext(ctx, input) + if err != nil { + return nil, err + } + for _, branch := range output.Branches { + repos = append(repos, &Repository{ + Organization: repo.Organization, + Repository: repo.Repository, + URL: repo.URL, + Branch: aws.StringValue(branch), + RepositoryId: repo.RepositoryId, + Labels: repo.Labels, + // getting SHA of the branch requires a separate GetBranch call. + // too expensive. for now, we just don't support it. + // SHA: "", + }) + } + input.NextToken = output.NextToken + if aws.StringValue(output.NextToken) == "" { + break + } + } + } + + return repos, nil +} + +func (p *AWSCodeCommitProvider) listRepoNames(ctx context.Context) ([]string, error) { + tagFilters := p.getTagFilters() + repoNames := make([]string, 0) + var err error + + if len(tagFilters) < 1 { + log.Debugf("no tag filer, calling codecommit api to list repos") + listReposInput := &codecommit.ListRepositoriesInput{} + var output *codecommit.ListRepositoriesOutput + for { + output, err = p.codeCommitClient.ListRepositoriesWithContext(ctx, listReposInput) + if err != nil { + break + } + for _, repo := range output.Repositories { + repoNames = append(repoNames, aws.StringValue(repo.RepositoryName)) + } + listReposInput.NextToken = output.NextToken + if aws.StringValue(output.NextToken) == "" { + break + } + } + } else { + log.Debugf("tag filer is specified, calling tagging api to list repos") + discoveryInput := &resourcegroupstaggingapi.GetResourcesInput{ + ResourceTypeFilters: aws.StringSlice([]string{resourceTypeCodeCommitRepository}), + TagFilters: tagFilters, + } + var output *resourcegroupstaggingapi.GetResourcesOutput + for { + output, err = p.taggingClient.GetResourcesWithContext(ctx, discoveryInput) + if err != nil { + break + } + for _, resource := range output.ResourceTagMappingList { + repoArn := aws.StringValue(resource.ResourceARN) + log.Debugf("discovered codecommit repo with arn %s", repoArn) + repoName, extractErr := getCodeCommitRepoName(repoArn) + if extractErr != nil { + log.Warnf("discovered codecommit repoArn %s cannot be parsed due to %v", repoArn, err) + continue + } + repoNames = append(repoNames, repoName) + } + discoveryInput.PaginationToken = output.PaginationToken + if aws.StringValue(output.PaginationToken) == "" { + break + } + } + } + return repoNames, err +} + +func (p *AWSCodeCommitProvider) getTagFilters() []*resourcegroupstaggingapi.TagFilter { + filters := make(map[string]*resourcegroupstaggingapi.TagFilter) + for _, tagFilter := range p.tagFilters { + filter, hasKey := filters[tagFilter.Key] + if !hasKey { + filter = &resourcegroupstaggingapi.TagFilter{ + Key: aws.String(tagFilter.Key), + } + filters[tagFilter.Key] = filter + } + if tagFilter.Value != "" { + filter.Values = append(filter.Values, aws.String(tagFilter.Value)) + } + } + return maps.Values(filters) +} + +func getCodeCommitRepoName(repoArn string) (string, error) { + parsedArn, err := arn.Parse(repoArn) + if err != nil { + return "", fmt.Errorf("failed to parse codecommit repository ARN: %w", err) + } + // see: https://docs.aws.amazon.com/codecommit/latest/userguide/auth-and-access-control-permissions-reference.html + // arn:aws:codecommit:region:account-id:repository-name + return parsedArn.Resource, nil +} + +// getCodeCommitFIPSEndpoint transforms provided https:// codecommit URL to a FIPS-compliant endpoint. +// note that the specified region must support FIPS, otherwise the returned URL won't be reachable +// see: https://docs.aws.amazon.com/codecommit/latest/userguide/regions.html#regions-git +func getCodeCommitFIPSEndpoint(repoUrl string) (string, error) { + if strings.HasPrefix(repoUrl, prefixGitUrlHttpsFIPS) { + log.Debugf("provided repoUrl %s is already a fips endpoint", repoUrl) + return repoUrl, nil + } + if !strings.HasPrefix(repoUrl, prefixGitUrlHttps) { + return "", fmt.Errorf("the provided https endpoint isn't recognized, cannot be transformed to FIPS endpoint: %s", repoUrl) + } + // we already have the prefix, so we guarantee to replace exactly the prefix only. + return strings.Replace(repoUrl, prefixGitUrlHttps, prefixGitUrlHttpsFIPS, 1), nil +} + +func hasAwsError(err error, codes ...string) bool { + if awsErr, ok := err.(awserr.Error); ok { + return slices.Contains(codes, awsErr.Code()) + } + return false +} + +// toAbsolutePath transforms a path input to absolute path, as required by AWS CodeCommit +// see https://docs.aws.amazon.com/codecommit/latest/APIReference/API_GetFolder.html +func toAbsolutePath(path string) string { + if filepath.IsAbs(path) { + return path + } + return filepath.ToSlash(filepath.Join("/", path)) +} + +func createAWSDiscoveryClients(_ context.Context, role string, region string) (*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, *codecommit.CodeCommit, error) { + podSession, err := session.NewSession() + if err != nil { + return nil, nil, fmt.Errorf("error creating new AWS pod session: %w", err) + } + discoverySession := podSession + // assume role if provided - this allows cross account CodeCommit repo discovery. + if role != "" { + log.Debugf("role %s is provided for AWS CodeCommit discovery", role) + assumeRoleCreds := stscreds.NewCredentials(podSession, role) + discoverySession, err = session.NewSession(&aws.Config{ + Credentials: assumeRoleCreds, + }) + if err != nil { + return nil, nil, fmt.Errorf("error creating new AWS discovery session: %s", err) + } + } else { + log.Debugf("role is not provided for AWS CodeCommit discovery, using pod role") + } + // use region explicitly if provided - this allows cross region CodeCommit repo discovery. + if region != "" { + log.Debugf("region %s is provided for AWS CodeCommit discovery", region) + discoverySession = discoverySession.Copy(&aws.Config{ + Region: aws.String(region), + }) + } else { + log.Debugf("region is not provided for AWS CodeCommit discovery, using pod region") + } + + taggingClient := resourcegroupstaggingapi.New(discoverySession) + codeCommitClient := codecommit.New(discoverySession) + + return taggingClient, codeCommitClient, nil +} diff --git a/applicationset/services/scm_provider/aws_codecommit/mocks/AWSCodeCommitClient.go b/applicationset/services/scm_provider/aws_codecommit/mocks/AWSCodeCommitClient.go new file mode 100644 index 0000000000000..b9d6f6a5d5956 --- /dev/null +++ b/applicationset/services/scm_provider/aws_codecommit/mocks/AWSCodeCommitClient.go @@ -0,0 +1,321 @@ +// Code generated by mockery v2.26.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + codecommit "github.com/aws/aws-sdk-go/service/codecommit" + + mock "github.com/stretchr/testify/mock" + + request "github.com/aws/aws-sdk-go/aws/request" +) + +// AWSCodeCommitClient is an autogenerated mock type for the AWSCodeCommitClient type +type AWSCodeCommitClient struct { + mock.Mock +} + +type AWSCodeCommitClient_Expecter struct { + mock *mock.Mock +} + +func (_m *AWSCodeCommitClient) EXPECT() *AWSCodeCommitClient_Expecter { + return &AWSCodeCommitClient_Expecter{mock: &_m.Mock} +} + +// GetFolderWithContext provides a mock function with given fields: _a0, _a1, _a2 +func (_m *AWSCodeCommitClient) GetFolderWithContext(_a0 context.Context, _a1 *codecommit.GetFolderInput, _a2 ...request.Option) (*codecommit.GetFolderOutput, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *codecommit.GetFolderOutput + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *codecommit.GetFolderInput, ...request.Option) (*codecommit.GetFolderOutput, error)); ok { + return rf(_a0, _a1, _a2...) + } + if rf, ok := ret.Get(0).(func(context.Context, *codecommit.GetFolderInput, ...request.Option) *codecommit.GetFolderOutput); ok { + r0 = rf(_a0, _a1, _a2...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*codecommit.GetFolderOutput) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *codecommit.GetFolderInput, ...request.Option) error); ok { + r1 = rf(_a0, _a1, _a2...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AWSCodeCommitClient_GetFolderWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFolderWithContext' +type AWSCodeCommitClient_GetFolderWithContext_Call struct { + *mock.Call +} + +// GetFolderWithContext is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *codecommit.GetFolderInput +// - _a2 ...request.Option +func (_e *AWSCodeCommitClient_Expecter) GetFolderWithContext(_a0 interface{}, _a1 interface{}, _a2 ...interface{}) *AWSCodeCommitClient_GetFolderWithContext_Call { + return &AWSCodeCommitClient_GetFolderWithContext_Call{Call: _e.mock.On("GetFolderWithContext", + append([]interface{}{_a0, _a1}, _a2...)...)} +} + +func (_c *AWSCodeCommitClient_GetFolderWithContext_Call) Run(run func(_a0 context.Context, _a1 *codecommit.GetFolderInput, _a2 ...request.Option)) *AWSCodeCommitClient_GetFolderWithContext_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]request.Option, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(request.Option) + } + } + run(args[0].(context.Context), args[1].(*codecommit.GetFolderInput), variadicArgs...) + }) + return _c +} + +func (_c *AWSCodeCommitClient_GetFolderWithContext_Call) Return(_a0 *codecommit.GetFolderOutput, _a1 error) *AWSCodeCommitClient_GetFolderWithContext_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AWSCodeCommitClient_GetFolderWithContext_Call) RunAndReturn(run func(context.Context, *codecommit.GetFolderInput, ...request.Option) (*codecommit.GetFolderOutput, error)) *AWSCodeCommitClient_GetFolderWithContext_Call { + _c.Call.Return(run) + return _c +} + +// GetRepositoryWithContext provides a mock function with given fields: _a0, _a1, _a2 +func (_m *AWSCodeCommitClient) GetRepositoryWithContext(_a0 context.Context, _a1 *codecommit.GetRepositoryInput, _a2 ...request.Option) (*codecommit.GetRepositoryOutput, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *codecommit.GetRepositoryOutput + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *codecommit.GetRepositoryInput, ...request.Option) (*codecommit.GetRepositoryOutput, error)); ok { + return rf(_a0, _a1, _a2...) + } + if rf, ok := ret.Get(0).(func(context.Context, *codecommit.GetRepositoryInput, ...request.Option) *codecommit.GetRepositoryOutput); ok { + r0 = rf(_a0, _a1, _a2...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*codecommit.GetRepositoryOutput) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *codecommit.GetRepositoryInput, ...request.Option) error); ok { + r1 = rf(_a0, _a1, _a2...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AWSCodeCommitClient_GetRepositoryWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetRepositoryWithContext' +type AWSCodeCommitClient_GetRepositoryWithContext_Call struct { + *mock.Call +} + +// GetRepositoryWithContext is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *codecommit.GetRepositoryInput +// - _a2 ...request.Option +func (_e *AWSCodeCommitClient_Expecter) GetRepositoryWithContext(_a0 interface{}, _a1 interface{}, _a2 ...interface{}) *AWSCodeCommitClient_GetRepositoryWithContext_Call { + return &AWSCodeCommitClient_GetRepositoryWithContext_Call{Call: _e.mock.On("GetRepositoryWithContext", + append([]interface{}{_a0, _a1}, _a2...)...)} +} + +func (_c *AWSCodeCommitClient_GetRepositoryWithContext_Call) Run(run func(_a0 context.Context, _a1 *codecommit.GetRepositoryInput, _a2 ...request.Option)) *AWSCodeCommitClient_GetRepositoryWithContext_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]request.Option, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(request.Option) + } + } + run(args[0].(context.Context), args[1].(*codecommit.GetRepositoryInput), variadicArgs...) + }) + return _c +} + +func (_c *AWSCodeCommitClient_GetRepositoryWithContext_Call) Return(_a0 *codecommit.GetRepositoryOutput, _a1 error) *AWSCodeCommitClient_GetRepositoryWithContext_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AWSCodeCommitClient_GetRepositoryWithContext_Call) RunAndReturn(run func(context.Context, *codecommit.GetRepositoryInput, ...request.Option) (*codecommit.GetRepositoryOutput, error)) *AWSCodeCommitClient_GetRepositoryWithContext_Call { + _c.Call.Return(run) + return _c +} + +// ListBranchesWithContext provides a mock function with given fields: _a0, _a1, _a2 +func (_m *AWSCodeCommitClient) ListBranchesWithContext(_a0 context.Context, _a1 *codecommit.ListBranchesInput, _a2 ...request.Option) (*codecommit.ListBranchesOutput, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *codecommit.ListBranchesOutput + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *codecommit.ListBranchesInput, ...request.Option) (*codecommit.ListBranchesOutput, error)); ok { + return rf(_a0, _a1, _a2...) + } + if rf, ok := ret.Get(0).(func(context.Context, *codecommit.ListBranchesInput, ...request.Option) *codecommit.ListBranchesOutput); ok { + r0 = rf(_a0, _a1, _a2...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*codecommit.ListBranchesOutput) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *codecommit.ListBranchesInput, ...request.Option) error); ok { + r1 = rf(_a0, _a1, _a2...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AWSCodeCommitClient_ListBranchesWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListBranchesWithContext' +type AWSCodeCommitClient_ListBranchesWithContext_Call struct { + *mock.Call +} + +// ListBranchesWithContext is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *codecommit.ListBranchesInput +// - _a2 ...request.Option +func (_e *AWSCodeCommitClient_Expecter) ListBranchesWithContext(_a0 interface{}, _a1 interface{}, _a2 ...interface{}) *AWSCodeCommitClient_ListBranchesWithContext_Call { + return &AWSCodeCommitClient_ListBranchesWithContext_Call{Call: _e.mock.On("ListBranchesWithContext", + append([]interface{}{_a0, _a1}, _a2...)...)} +} + +func (_c *AWSCodeCommitClient_ListBranchesWithContext_Call) Run(run func(_a0 context.Context, _a1 *codecommit.ListBranchesInput, _a2 ...request.Option)) *AWSCodeCommitClient_ListBranchesWithContext_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]request.Option, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(request.Option) + } + } + run(args[0].(context.Context), args[1].(*codecommit.ListBranchesInput), variadicArgs...) + }) + return _c +} + +func (_c *AWSCodeCommitClient_ListBranchesWithContext_Call) Return(_a0 *codecommit.ListBranchesOutput, _a1 error) *AWSCodeCommitClient_ListBranchesWithContext_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AWSCodeCommitClient_ListBranchesWithContext_Call) RunAndReturn(run func(context.Context, *codecommit.ListBranchesInput, ...request.Option) (*codecommit.ListBranchesOutput, error)) *AWSCodeCommitClient_ListBranchesWithContext_Call { + _c.Call.Return(run) + return _c +} + +// ListRepositoriesWithContext provides a mock function with given fields: _a0, _a1, _a2 +func (_m *AWSCodeCommitClient) ListRepositoriesWithContext(_a0 context.Context, _a1 *codecommit.ListRepositoriesInput, _a2 ...request.Option) (*codecommit.ListRepositoriesOutput, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *codecommit.ListRepositoriesOutput + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *codecommit.ListRepositoriesInput, ...request.Option) (*codecommit.ListRepositoriesOutput, error)); ok { + return rf(_a0, _a1, _a2...) + } + if rf, ok := ret.Get(0).(func(context.Context, *codecommit.ListRepositoriesInput, ...request.Option) *codecommit.ListRepositoriesOutput); ok { + r0 = rf(_a0, _a1, _a2...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*codecommit.ListRepositoriesOutput) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *codecommit.ListRepositoriesInput, ...request.Option) error); ok { + r1 = rf(_a0, _a1, _a2...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AWSCodeCommitClient_ListRepositoriesWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListRepositoriesWithContext' +type AWSCodeCommitClient_ListRepositoriesWithContext_Call struct { + *mock.Call +} + +// ListRepositoriesWithContext is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *codecommit.ListRepositoriesInput +// - _a2 ...request.Option +func (_e *AWSCodeCommitClient_Expecter) ListRepositoriesWithContext(_a0 interface{}, _a1 interface{}, _a2 ...interface{}) *AWSCodeCommitClient_ListRepositoriesWithContext_Call { + return &AWSCodeCommitClient_ListRepositoriesWithContext_Call{Call: _e.mock.On("ListRepositoriesWithContext", + append([]interface{}{_a0, _a1}, _a2...)...)} +} + +func (_c *AWSCodeCommitClient_ListRepositoriesWithContext_Call) Run(run func(_a0 context.Context, _a1 *codecommit.ListRepositoriesInput, _a2 ...request.Option)) *AWSCodeCommitClient_ListRepositoriesWithContext_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]request.Option, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(request.Option) + } + } + run(args[0].(context.Context), args[1].(*codecommit.ListRepositoriesInput), variadicArgs...) + }) + return _c +} + +func (_c *AWSCodeCommitClient_ListRepositoriesWithContext_Call) Return(_a0 *codecommit.ListRepositoriesOutput, _a1 error) *AWSCodeCommitClient_ListRepositoriesWithContext_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AWSCodeCommitClient_ListRepositoriesWithContext_Call) RunAndReturn(run func(context.Context, *codecommit.ListRepositoriesInput, ...request.Option) (*codecommit.ListRepositoriesOutput, error)) *AWSCodeCommitClient_ListRepositoriesWithContext_Call { + _c.Call.Return(run) + return _c +} + +type mockConstructorTestingTNewAWSCodeCommitClient interface { + mock.TestingT + Cleanup(func()) +} + +// NewAWSCodeCommitClient creates a new instance of AWSCodeCommitClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewAWSCodeCommitClient(t mockConstructorTestingTNewAWSCodeCommitClient) *AWSCodeCommitClient { + mock := &AWSCodeCommitClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/applicationset/services/scm_provider/aws_codecommit/mocks/AWSTaggingClient.go b/applicationset/services/scm_provider/aws_codecommit/mocks/AWSTaggingClient.go new file mode 100644 index 0000000000000..9acd8979b7818 --- /dev/null +++ b/applicationset/services/scm_provider/aws_codecommit/mocks/AWSTaggingClient.go @@ -0,0 +1,110 @@ +// Code generated by mockery v2.26.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + request "github.com/aws/aws-sdk-go/aws/request" + mock "github.com/stretchr/testify/mock" + + resourcegroupstaggingapi "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" +) + +// AWSTaggingClient is an autogenerated mock type for the AWSTaggingClient type +type AWSTaggingClient struct { + mock.Mock +} + +type AWSTaggingClient_Expecter struct { + mock *mock.Mock +} + +func (_m *AWSTaggingClient) EXPECT() *AWSTaggingClient_Expecter { + return &AWSTaggingClient_Expecter{mock: &_m.Mock} +} + +// GetResourcesWithContext provides a mock function with given fields: _a0, _a1, _a2 +func (_m *AWSTaggingClient) GetResourcesWithContext(_a0 context.Context, _a1 *resourcegroupstaggingapi.GetResourcesInput, _a2 ...request.Option) (*resourcegroupstaggingapi.GetResourcesOutput, error) { + _va := make([]interface{}, len(_a2)) + for _i := range _a2 { + _va[_i] = _a2[_i] + } + var _ca []interface{} + _ca = append(_ca, _a0, _a1) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *resourcegroupstaggingapi.GetResourcesOutput + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *resourcegroupstaggingapi.GetResourcesInput, ...request.Option) (*resourcegroupstaggingapi.GetResourcesOutput, error)); ok { + return rf(_a0, _a1, _a2...) + } + if rf, ok := ret.Get(0).(func(context.Context, *resourcegroupstaggingapi.GetResourcesInput, ...request.Option) *resourcegroupstaggingapi.GetResourcesOutput); ok { + r0 = rf(_a0, _a1, _a2...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*resourcegroupstaggingapi.GetResourcesOutput) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *resourcegroupstaggingapi.GetResourcesInput, ...request.Option) error); ok { + r1 = rf(_a0, _a1, _a2...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AWSTaggingClient_GetResourcesWithContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetResourcesWithContext' +type AWSTaggingClient_GetResourcesWithContext_Call struct { + *mock.Call +} + +// GetResourcesWithContext is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 *resourcegroupstaggingapi.GetResourcesInput +// - _a2 ...request.Option +func (_e *AWSTaggingClient_Expecter) GetResourcesWithContext(_a0 interface{}, _a1 interface{}, _a2 ...interface{}) *AWSTaggingClient_GetResourcesWithContext_Call { + return &AWSTaggingClient_GetResourcesWithContext_Call{Call: _e.mock.On("GetResourcesWithContext", + append([]interface{}{_a0, _a1}, _a2...)...)} +} + +func (_c *AWSTaggingClient_GetResourcesWithContext_Call) Run(run func(_a0 context.Context, _a1 *resourcegroupstaggingapi.GetResourcesInput, _a2 ...request.Option)) *AWSTaggingClient_GetResourcesWithContext_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]request.Option, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(request.Option) + } + } + run(args[0].(context.Context), args[1].(*resourcegroupstaggingapi.GetResourcesInput), variadicArgs...) + }) + return _c +} + +func (_c *AWSTaggingClient_GetResourcesWithContext_Call) Return(_a0 *resourcegroupstaggingapi.GetResourcesOutput, _a1 error) *AWSTaggingClient_GetResourcesWithContext_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AWSTaggingClient_GetResourcesWithContext_Call) RunAndReturn(run func(context.Context, *resourcegroupstaggingapi.GetResourcesInput, ...request.Option) (*resourcegroupstaggingapi.GetResourcesOutput, error)) *AWSTaggingClient_GetResourcesWithContext_Call { + _c.Call.Return(run) + return _c +} + +type mockConstructorTestingTNewAWSTaggingClient interface { + mock.TestingT + Cleanup(func()) +} + +// NewAWSTaggingClient creates a new instance of AWSTaggingClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewAWSTaggingClient(t mockConstructorTestingTNewAWSTaggingClient) *AWSTaggingClient { + mock := &AWSTaggingClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/applicationset/services/scm_provider/aws_codecommit_test.go b/applicationset/services/scm_provider/aws_codecommit_test.go new file mode 100644 index 0000000000000..3a4f7c1a9a6a8 --- /dev/null +++ b/applicationset/services/scm_provider/aws_codecommit_test.go @@ -0,0 +1,483 @@ +package scm_provider + +import ( + "context" + "errors" + "sort" + "testing" + + "github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider/aws_codecommit/mocks" + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/codecommit" + "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" + "github.com/google/go-cmp/cmp" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +type awsCodeCommitTestRepository struct { + name string + id string + arn string + accountId string + defaultBranch string + expectedCloneUrl string + getRepositoryError error + getRepositoryNilMetadata bool + valid bool +} + +func TestAWSCodeCommitListRepos(t *testing.T) { + testCases := []struct { + name string + repositories []*awsCodeCommitTestRepository + cloneProtocol string + tagFilters []*v1alpha1.TagFilter + expectTagFilters []*resourcegroupstaggingapi.TagFilter + listRepositoryError error + expectOverallError bool + expectListAtCodeCommit bool + }{ + { + name: "ListRepos by tag with https", + cloneProtocol: "https", + repositories: []*awsCodeCommitTestRepository{ + { + name: "repo1", + id: "8235624d-d248-4df9-a983-2558b01dbe83", + arn: "arn:aws:codecommit:us-east-1:111111111111:repo1", + defaultBranch: "main", + expectedCloneUrl: "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1", + valid: true, + }, + }, + tagFilters: []*v1alpha1.TagFilter{ + {Key: "key1", Value: "value1"}, + {Key: "key1", Value: "value2"}, + {Key: "key2"}, + }, + expectTagFilters: []*resourcegroupstaggingapi.TagFilter{ + {Key: aws.String("key1"), Values: aws.StringSlice([]string{"value1", "value2"})}, + {Key: aws.String("key2")}, + }, + expectOverallError: false, + expectListAtCodeCommit: false, + }, + { + name: "ListRepos by tag with https-fips", + cloneProtocol: "https-fips", + repositories: []*awsCodeCommitTestRepository{ + { + name: "repo1", + id: "8235624d-d248-4df9-a983-2558b01dbe83", + arn: "arn:aws:codecommit:us-east-1:111111111111:repo1", + defaultBranch: "main", + expectedCloneUrl: "https://git-codecommit-fips.us-east-1.amazonaws.com/v1/repos/repo1", + valid: true, + }, + }, + tagFilters: []*v1alpha1.TagFilter{ + {Key: "key1"}, + }, + expectTagFilters: []*resourcegroupstaggingapi.TagFilter{ + {Key: aws.String("key1")}, + }, + expectOverallError: false, + expectListAtCodeCommit: false, + }, + { + name: "ListRepos without tag with invalid repo", + cloneProtocol: "ssh", + repositories: []*awsCodeCommitTestRepository{ + { + name: "repo1", + id: "8235624d-d248-4df9-a983-2558b01dbe83", + arn: "arn:aws:codecommit:us-east-1:111111111111:repo1", + defaultBranch: "main", + expectedCloneUrl: "ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1", + valid: true, + }, + { + name: "repo2", + id: "640d5859-d265-4e27-a9fa-e0731eb13ed7", + arn: "arn:aws:codecommit:us-east-1:111111111111:repo2", + valid: false, + }, + { + name: "repo3-nil-metadata", + id: "24a6ee96-d3a0-4be6-a595-c5e5b1ab1617", + arn: "arn:aws:codecommit:us-east-1:111111111111:repo3-nil-metadata", + getRepositoryNilMetadata: true, + valid: false, + }, + }, + expectOverallError: false, + expectListAtCodeCommit: true, + }, + { + name: "ListRepos with invalid protocol", + cloneProtocol: "invalid-protocol", + repositories: []*awsCodeCommitTestRepository{ + { + name: "repo1", + id: "8235624d-d248-4df9-a983-2558b01dbe83", + arn: "arn:aws:codecommit:us-east-1:111111111111:repo1", + defaultBranch: "main", + valid: true, + }, + }, + expectOverallError: true, + expectListAtCodeCommit: true, + }, + { + name: "ListRepos error on listRepos", + cloneProtocol: "https", + listRepositoryError: errors.New("list repo error"), + expectOverallError: true, + expectListAtCodeCommit: true, + }, + { + name: "ListRepos error on getRepo", + cloneProtocol: "https", + repositories: []*awsCodeCommitTestRepository{ + { + name: "repo1", + id: "8235624d-d248-4df9-a983-2558b01dbe83", + arn: "arn:aws:codecommit:us-east-1:111111111111:repo1", + defaultBranch: "main", + getRepositoryError: errors.New("get repo error"), + valid: true, + }, + }, + expectOverallError: true, + expectListAtCodeCommit: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + codeCommitClient := mocks.NewAWSCodeCommitClient(t) + taggingClient := mocks.NewAWSTaggingClient(t) + ctx := context.Background() + codecommitRepoNameIdPairs := make([]*codecommit.RepositoryNameIdPair, 0) + resourceTaggings := make([]*resourcegroupstaggingapi.ResourceTagMapping, 0) + validRepositories := make([]*awsCodeCommitTestRepository, 0) + + for _, repo := range testCase.repositories { + repoMetadata := &codecommit.RepositoryMetadata{ + AccountId: aws.String(repo.accountId), + Arn: aws.String(repo.arn), + CloneUrlHttp: aws.String("https://git-codecommit.us-east-1.amazonaws.com/v1/repos/" + repo.name), + CloneUrlSsh: aws.String("ssh://git-codecommit.us-east-1.amazonaws.com/v1/repos/" + repo.name), + DefaultBranch: aws.String(repo.defaultBranch), + RepositoryId: aws.String(repo.id), + RepositoryName: aws.String(repo.name), + } + if repo.getRepositoryNilMetadata { + repoMetadata = nil + } + codeCommitClient.EXPECT(). + GetRepositoryWithContext(ctx, &codecommit.GetRepositoryInput{RepositoryName: aws.String(repo.name)}). + Return(&codecommit.GetRepositoryOutput{RepositoryMetadata: repoMetadata}, repo.getRepositoryError) + codecommitRepoNameIdPairs = append(codecommitRepoNameIdPairs, &codecommit.RepositoryNameIdPair{ + RepositoryId: aws.String(repo.id), + RepositoryName: aws.String(repo.name), + }) + resourceTaggings = append(resourceTaggings, &resourcegroupstaggingapi.ResourceTagMapping{ + ResourceARN: aws.String(repo.arn), + }) + if repo.valid { + validRepositories = append(validRepositories, repo) + } + } + + if testCase.expectListAtCodeCommit { + codeCommitClient.EXPECT(). + ListRepositoriesWithContext(ctx, &codecommit.ListRepositoriesInput{}). + Return(&codecommit.ListRepositoriesOutput{ + Repositories: codecommitRepoNameIdPairs, + }, testCase.listRepositoryError) + } else { + taggingClient.EXPECT(). + GetResourcesWithContext(ctx, mock.MatchedBy(equalIgnoringTagFilterOrder(&resourcegroupstaggingapi.GetResourcesInput{ + TagFilters: testCase.expectTagFilters, + ResourceTypeFilters: aws.StringSlice([]string{resourceTypeCodeCommitRepository}), + }))). + Return(&resourcegroupstaggingapi.GetResourcesOutput{ + ResourceTagMappingList: resourceTaggings, + }, testCase.listRepositoryError) + } + + provider := &AWSCodeCommitProvider{ + codeCommitClient: codeCommitClient, + taggingClient: taggingClient, + tagFilters: testCase.tagFilters, + } + repos, err := provider.ListRepos(ctx, testCase.cloneProtocol) + if testCase.expectOverallError { + assert.Error(t, err) + } else { + assert.Len(t, repos, len(validRepositories)) + for i, repo := range repos { + originRepo := validRepositories[i] + assert.Equal(t, originRepo.accountId, repo.Organization) + assert.Equal(t, originRepo.name, repo.Repository) + assert.Equal(t, originRepo.id, repo.RepositoryId) + assert.Equal(t, originRepo.defaultBranch, repo.Branch) + assert.Equal(t, originRepo.expectedCloneUrl, repo.URL) + assert.Empty(t, repo.SHA, "SHA is always empty") + } + } + }) + } +} + +func TestAWSCodeCommitRepoHasPath(t *testing.T) { + organization := "111111111111" + repoName := "repo1" + branch := "main" + + testCases := []struct { + name string + path string + expectedGetFolderPath string + getFolderOutput *codecommit.GetFolderOutput + getFolderError error + expectOverallError bool + expectedResult bool + }{ + { + name: "RepoHasPath on regular file", + path: "lib/config.yaml", + expectedGetFolderPath: "/lib", + getFolderOutput: &codecommit.GetFolderOutput{ + Files: []*codecommit.File{ + {RelativePath: aws.String("config.yaml")}, + }, + }, + expectOverallError: false, + expectedResult: true, + }, + { + name: "RepoHasPath on folder", + path: "lib/config", + expectedGetFolderPath: "/lib", + getFolderOutput: &codecommit.GetFolderOutput{ + SubFolders: []*codecommit.Folder{ + {RelativePath: aws.String("config")}, + }, + }, + expectOverallError: false, + expectedResult: true, + }, + { + name: "RepoHasPath on submodules", + path: "/lib/submodule/", + expectedGetFolderPath: "/lib", + getFolderOutput: &codecommit.GetFolderOutput{ + SubModules: []*codecommit.SubModule{ + {RelativePath: aws.String("submodule")}, + }, + }, + expectOverallError: false, + expectedResult: true, + }, + { + name: "RepoHasPath on symlink", + path: "./lib/service.json", + expectedGetFolderPath: "/lib", + getFolderOutput: &codecommit.GetFolderOutput{ + SymbolicLinks: []*codecommit.SymbolicLink{ + {RelativePath: aws.String("service.json")}, + }, + }, + expectOverallError: false, + expectedResult: true, + }, + { + name: "RepoHasPath when no match", + path: "no-match.json", + expectedGetFolderPath: "/", + getFolderOutput: &codecommit.GetFolderOutput{ + Files: []*codecommit.File{ + {RelativePath: aws.String("config.yaml")}, + }, + SubFolders: []*codecommit.Folder{ + {RelativePath: aws.String("config")}, + }, + SubModules: []*codecommit.SubModule{ + {RelativePath: aws.String("submodule")}, + }, + SymbolicLinks: []*codecommit.SymbolicLink{ + {RelativePath: aws.String("service.json")}, + }, + }, + expectOverallError: false, + expectedResult: false, + }, + { + name: "RepoHasPath when parent folder not found", + path: "lib/submodule", + expectedGetFolderPath: "/lib", + getFolderError: &codecommit.FolderDoesNotExistException{}, + expectOverallError: false, + }, + { + name: "RepoHasPath when unknown error", + path: "lib/submodule", + expectedGetFolderPath: "/lib", + getFolderError: errors.New("unknown error"), + expectOverallError: true, + }, + { + name: "RepoHasPath on root folder - './'", + path: "./", + expectOverallError: false, + expectedResult: true, + }, + { + name: "RepoHasPath on root folder - '/'", + path: "/", + expectOverallError: false, + expectedResult: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + codeCommitClient := mocks.NewAWSCodeCommitClient(t) + taggingClient := mocks.NewAWSTaggingClient(t) + ctx := context.Background() + if testCase.expectedGetFolderPath != "" { + codeCommitClient.EXPECT(). + GetFolderWithContext(ctx, &codecommit.GetFolderInput{ + CommitSpecifier: aws.String(branch), + FolderPath: aws.String(testCase.expectedGetFolderPath), + RepositoryName: aws.String(repoName), + }). + Return(testCase.getFolderOutput, testCase.getFolderError) + } + provider := &AWSCodeCommitProvider{ + codeCommitClient: codeCommitClient, + taggingClient: taggingClient, + } + actual, err := provider.RepoHasPath(ctx, &Repository{ + Organization: organization, + Repository: repoName, + Branch: branch, + }, testCase.path) + if testCase.expectOverallError { + assert.Error(t, err) + } else { + assert.Equal(t, testCase.expectedResult, actual) + } + }) + } +} + +func TestAWSCodeCommitGetBranches(t *testing.T) { + name := "repo1" + id := "1a64adc4-2fb5-4abd-afe7-127984ba83c0" + defaultBranch := "main" + organization := "111111111111" + cloneUrl := "https://git-codecommit.us-east-1.amazonaws.com/v1/repos/repo1" + + testCases := []struct { + name string + branches []string + apiError error + expectOverallError bool + allBranches bool + }{ + { + name: "GetBranches all branches", + branches: []string{"main", "feature/codecommit", "chore/go-upgrade"}, + allBranches: true, + }, + { + name: "GetBranches default branch only", + allBranches: false, + }, + { + name: "GetBranches default branch only", + allBranches: false, + }, + { + name: "GetBranches all branches on api error", + apiError: errors.New("api error"), + expectOverallError: true, + allBranches: true, + }, + { + name: "GetBranches default branch on api error", + apiError: errors.New("api error"), + expectOverallError: true, + allBranches: false, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + codeCommitClient := mocks.NewAWSCodeCommitClient(t) + taggingClient := mocks.NewAWSTaggingClient(t) + ctx := context.Background() + if testCase.allBranches { + codeCommitClient.EXPECT(). + ListBranchesWithContext(ctx, &codecommit.ListBranchesInput{ + RepositoryName: aws.String(name), + }). + Return(&codecommit.ListBranchesOutput{Branches: aws.StringSlice(testCase.branches)}, testCase.apiError) + } else { + codeCommitClient.EXPECT(). + GetRepositoryWithContext(ctx, &codecommit.GetRepositoryInput{RepositoryName: aws.String(name)}). + Return(&codecommit.GetRepositoryOutput{RepositoryMetadata: &codecommit.RepositoryMetadata{ + AccountId: aws.String(organization), + DefaultBranch: aws.String(defaultBranch), + }}, testCase.apiError) + } + provider := &AWSCodeCommitProvider{ + codeCommitClient: codeCommitClient, + taggingClient: taggingClient, + allBranches: testCase.allBranches, + } + actual, err := provider.GetBranches(ctx, &Repository{ + Organization: organization, + Repository: name, + URL: cloneUrl, + RepositoryId: id, + }) + if testCase.expectOverallError { + assert.Error(t, err) + } else { + assertCopiedProperties := func(repo *Repository) { + assert.Equal(t, id, repo.RepositoryId) + assert.Equal(t, name, repo.Repository) + assert.Equal(t, cloneUrl, repo.URL) + assert.Equal(t, organization, repo.Organization) + assert.Empty(t, repo.SHA) + } + actualBranches := make([]string, 0) + for _, repo := range actual { + assertCopiedProperties(repo) + actualBranches = append(actualBranches, repo.Branch) + } + if testCase.allBranches { + assert.ElementsMatch(t, testCase.branches, actualBranches) + } else { + assert.ElementsMatch(t, []string{defaultBranch}, actualBranches) + } + } + }) + } +} + +// equalIgnoringTagFilterOrder provides an argumentMatcher function that can be used to compare equality of GetResourcesInput ignoring the tagFilter ordering. +func equalIgnoringTagFilterOrder(expected *resourcegroupstaggingapi.GetResourcesInput) func(*resourcegroupstaggingapi.GetResourcesInput) bool { + return func(actual *resourcegroupstaggingapi.GetResourcesInput) bool { + sort.Slice(actual.TagFilters, func(i, j int) bool { + return *actual.TagFilters[i].Key < *actual.TagFilters[j].Key + }) + return cmp.Equal(expected, actual) + } +} diff --git a/applicationset/services/scm_provider/bitbucket_cloud.go b/applicationset/services/scm_provider/bitbucket_cloud.go index f2af9d44cdec9..3c453f6b9c17d 100644 --- a/applicationset/services/scm_provider/bitbucket_cloud.go +++ b/applicationset/services/scm_provider/bitbucket_cloud.go @@ -29,7 +29,7 @@ func (c *ExtendedClient) GetContents(repo *Repository, path string) (bool, error urlStr += fmt.Sprintf("/repositories/%s/%s/src/%s/%s?format=meta", c.owner, repo.Repository, repo.SHA, path) body := strings.NewReader("") - req, err := http.NewRequest("GET", urlStr, body) + req, err := http.NewRequest(http.MethodGet, urlStr, body) if err != nil { return false, err } diff --git a/applicationset/services/scm_provider/bitbucket_cloud_test.go b/applicationset/services/scm_provider/bitbucket_cloud_test.go index 359eac17e3f11..fca03e1693ade 100644 --- a/applicationset/services/scm_provider/bitbucket_cloud_test.go +++ b/applicationset/services/scm_provider/bitbucket_cloud_test.go @@ -5,7 +5,6 @@ import ( "fmt" "net/http" "net/http/httptest" - "os" "testing" "github.com/stretchr/testify/assert" @@ -62,7 +61,7 @@ func TestBitbucketHasRepo(t *testing.T) { })) defer func() { testServer.Close() }() - os.Setenv("BITBUCKET_API_BASE_URL", testServer.URL) + t.Setenv("BITBUCKET_API_BASE_URL", testServer.URL) cases := []struct { name, path, repo, owner, sha string status int @@ -449,7 +448,7 @@ func TestBitbucketListRepos(t *testing.T) { })) defer func() { testServer.Close() }() - os.Setenv("BITBUCKET_API_BASE_URL", testServer.URL) + t.Setenv("BITBUCKET_API_BASE_URL", testServer.URL) cases := []struct { name, proto, owner string hasError, allBranches bool diff --git a/applicationset/services/scm_provider/bitbucket_server.go b/applicationset/services/scm_provider/bitbucket_server.go index f8a08bc4ccfc0..9e46569512156 100644 --- a/applicationset/services/scm_provider/bitbucket_server.go +++ b/applicationset/services/scm_provider/bitbucket_server.go @@ -3,6 +3,7 @@ package scm_provider import ( "context" "fmt" + "io" "github.com/argoproj/argo-cd/v2/applicationset/utils" bitbucketv1 "github.com/gfleury/go-bitbucket-v1" @@ -183,8 +184,9 @@ func (b *BitbucketServerProvider) listBranches(repo *Repository) ([]bitbucketv1. func (b *BitbucketServerProvider) getDefaultBranch(org string, repo string) (*bitbucketv1.Branch, error) { response, err := b.client.DefaultApi.GetDefaultBranch(org, repo) - if response != nil && response.StatusCode == 404 { - // There's no default branch i.e. empty repo, not an error + // The API will return 404 if a default branch is set but doesn't exist. In case the repo is empty and default branch is unset, + // we will get an EOF and a nil response. + if (response != nil && response.StatusCode == 404) || (response == nil && err == io.EOF) { return nil, nil } if err != nil { diff --git a/applicationset/services/scm_provider/bitbucket_server_test.go b/applicationset/services/scm_provider/bitbucket_server_test.go index 986e03a895655..d403bd72caaac 100644 --- a/applicationset/services/scm_provider/bitbucket_server_test.go +++ b/applicationset/services/scm_provider/bitbucket_server_test.go @@ -347,7 +347,7 @@ func TestGetBranchesMissingDefault(t *testing.T) { assert.Empty(t, r.Header.Get("Authorization")) switch r.RequestURI { case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default": - http.Error(w, "Not found", 404) + http.Error(w, "Not found", http.StatusNotFound) } defaultHandler(t)(w, r) })) @@ -365,12 +365,34 @@ func TestGetBranchesMissingDefault(t *testing.T) { assert.Empty(t, repos) } +func TestGetBranchesEmptyRepo(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Empty(t, r.Header.Get("Authorization")) + switch r.RequestURI { + case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default": + return + } + })) + defer ts.Close() + provider, err := NewBitbucketServerProviderNoAuth(context.Background(), ts.URL, "PROJECT", false) + assert.NoError(t, err) + repos, err := provider.GetBranches(context.Background(), &Repository{ + Organization: "PROJECT", + Repository: "REPO", + URL: "ssh://git@mycompany.bitbucket.org/PROJECT/REPO.git", + Labels: []string{}, + RepositoryId: 1, + }) + assert.Empty(t, repos) + assert.NoError(t, err) +} + func TestGetBranchesErrorDefaultBranch(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Empty(t, r.Header.Get("Authorization")) switch r.RequestURI { case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default": - http.Error(w, "Internal server error", 500) + http.Error(w, "Internal server error", http.StatusInternalServerError) } defaultHandler(t)(w, r) })) @@ -442,7 +464,7 @@ func TestListReposMissingDefaultBranch(t *testing.T) { assert.Empty(t, r.Header.Get("Authorization")) switch r.RequestURI { case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default": - http.Error(w, "Not found", 404) + http.Error(w, "Not found", http.StatusNotFound) } defaultHandler(t)(w, r) })) @@ -459,7 +481,7 @@ func TestListReposErrorDefaultBranch(t *testing.T) { assert.Empty(t, r.Header.Get("Authorization")) switch r.RequestURI { case "/rest/api/1.0/projects/PROJECT/repos/REPO/branches/default": - http.Error(w, "Internal server error", 500) + http.Error(w, "Internal server error", http.StatusInternalServerError) } defaultHandler(t)(w, r) })) @@ -516,17 +538,17 @@ func TestBitbucketServerHasPath(t *testing.T) { _, err = io.WriteString(w, `{"type":"FILE"}`) case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/anotherpkg/missing.txt?at=main&limit=100&type=true": - http.Error(w, "The path \"anotherpkg/missing.txt\" does not exist at revision \"main\"", 404) + http.Error(w, "The path \"anotherpkg/missing.txt\" does not exist at revision \"main\"", http.StatusNotFound) case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/notathing?at=main&limit=100&type=true": - http.Error(w, "The path \"notathing\" does not exist at revision \"main\"", 404) + http.Error(w, "The path \"notathing\" does not exist at revision \"main\"", http.StatusNotFound) case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/return-redirect?at=main&limit=100&type=true": - http.Redirect(w, r, "http://"+r.Host+"/rest/api/1.0/projects/PROJECT/repos/REPO/browse/redirected?at=main&limit=100&type=true", 301) + http.Redirect(w, r, "http://"+r.Host+"/rest/api/1.0/projects/PROJECT/repos/REPO/browse/redirected?at=main&limit=100&type=true", http.StatusMovedPermanently) case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/redirected?at=main&limit=100&type=true": _, err = io.WriteString(w, `{"type":"DIRECTORY"}`) case "/rest/api/1.0/projects/PROJECT/repos/REPO/browse/unauthorized-response?at=main&limit=100&type=true": - http.Error(w, "Authentication failed", 401) + http.Error(w, "Authentication failed", http.StatusUnauthorized) default: t.Fail() diff --git a/applicationset/services/scm_provider/gitea.go b/applicationset/services/scm_provider/gitea.go index d00916051ed05..25554d52af85f 100644 --- a/applicationset/services/scm_provider/gitea.go +++ b/applicationset/services/scm_provider/gitea.go @@ -27,11 +27,13 @@ func NewGiteaProvider(ctx context.Context, owner, token, url string, allBranches if insecure { cookieJar, _ := cookiejar.New(nil) + tr := http.DefaultTransport.(*http.Transport).Clone() + tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + httpClient = &http.Client{ - Jar: cookieJar, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - }} + Jar: cookieJar, + Transport: tr, + } } client, err := gitea.NewClient(url, gitea.SetToken(token), gitea.SetHTTPClient(httpClient)) if err != nil { @@ -47,7 +49,7 @@ func NewGiteaProvider(ctx context.Context, owner, token, url string, allBranches func (g *GiteaProvider) GetBranches(ctx context.Context, repo *Repository) ([]*Repository, error) { if !g.allBranches { branch, status, err := g.client.GetRepoBranch(g.owner, repo.Repository, repo.Branch) - if status.StatusCode == 404 { + if status.StatusCode == http.StatusNotFound { return nil, fmt.Errorf("got 404 while getting default branch %q for repo %q - check your repo config: %w", repo.Branch, repo.Repository, err) } if err != nil { diff --git a/applicationset/services/scm_provider/gitea_test.go b/applicationset/services/scm_provider/gitea_test.go index b8b8af44263b9..3d17e3175c4f8 100644 --- a/applicationset/services/scm_provider/gitea_test.go +++ b/applicationset/services/scm_provider/gitea_test.go @@ -247,7 +247,7 @@ func giteaMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) { _, err := io.WriteString(w, testdata.ReposGiteaGoSdkContentsGiteaResponse) require.NoError(t, err) case "/api/v1/repos/gitea/go-sdk/contents/notathing?ref=master": - w.WriteHeader(404) + w.WriteHeader(http.StatusNotFound) _, err := io.WriteString(w, `{"errors":["object does not exist [id: , rel_path: notathing]"],"message":"GetContentsOrList","url":"https://gitea.com/api/swagger"}`) require.NoError(t, err) default: diff --git a/applicationset/services/scm_provider/github.go b/applicationset/services/scm_provider/github.go index e05b37b8b958c..1a6edae5837e9 100644 --- a/applicationset/services/scm_provider/github.go +++ b/applicationset/services/scm_provider/github.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "net/http" "os" "github.com/google/go-github/v35/github" @@ -123,7 +124,7 @@ func (g *GithubProvider) listBranches(ctx context.Context, repo *Repository) ([] if err != nil { var githubErrorResponse *github.ErrorResponse if errors.As(err, &githubErrorResponse) { - if githubErrorResponse.Response.StatusCode == 404 { + if githubErrorResponse.Response.StatusCode == http.StatusNotFound { // Default branch doesn't exist, so the repo is empty. return []github.Branch{}, nil } diff --git a/applicationset/services/scm_provider/github_test.go b/applicationset/services/scm_provider/github_test.go index 8314216cd20d4..d413250f03126 100644 --- a/applicationset/services/scm_provider/github_test.go +++ b/applicationset/services/scm_provider/github_test.go @@ -196,7 +196,7 @@ func githubMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) { t.Fail() } default: - w.WriteHeader(404) + w.WriteHeader(http.StatusNotFound) } } } diff --git a/applicationset/services/scm_provider/gitlab.go b/applicationset/services/scm_provider/gitlab.go index cbd0f36293515..ca174de540887 100644 --- a/applicationset/services/scm_provider/gitlab.go +++ b/applicationset/services/scm_provider/gitlab.go @@ -3,41 +3,54 @@ package scm_provider import ( "context" "fmt" + "net/http" "os" pathpkg "path" - gitlab "github.com/xanzy/go-gitlab" + "github.com/argoproj/argo-cd/v2/applicationset/utils" + "github.com/hashicorp/go-retryablehttp" + "github.com/xanzy/go-gitlab" ) type GitlabProvider struct { - client *gitlab.Client - organization string - allBranches bool - includeSubgroups bool + client *gitlab.Client + organization string + allBranches bool + includeSubgroups bool + includeSharedProjects bool + topic string } var _ SCMProviderService = &GitlabProvider{} -func NewGitlabProvider(ctx context.Context, organization string, token string, url string, allBranches, includeSubgroups bool) (*GitlabProvider, error) { +func NewGitlabProvider(ctx context.Context, organization string, token string, url string, allBranches, includeSubgroups, includeSharedProjects, insecure bool, scmRootCAPath, topic string) (*GitlabProvider, error) { // Undocumented environment variable to set a default token, to be used in testing to dodge anonymous rate limits. if token == "" { token = os.Getenv("GITLAB_TOKEN") } var client *gitlab.Client + + tr := http.DefaultTransport.(*http.Transport).Clone() + tr.TLSClientConfig = utils.GetTlsConfig(scmRootCAPath, insecure) + + retryClient := retryablehttp.NewClient() + retryClient.HTTPClient.Transport = tr + if url == "" { var err error - client, err = gitlab.NewClient(token) + client, err = gitlab.NewClient(token, gitlab.WithHTTPClient(retryClient.HTTPClient)) if err != nil { return nil, err } } else { var err error - client, err = gitlab.NewClient(token, gitlab.WithBaseURL(url)) + client, err = gitlab.NewClient(token, gitlab.WithBaseURL(url), gitlab.WithHTTPClient(retryClient.HTTPClient)) if err != nil { return nil, err } } - return &GitlabProvider{client: client, organization: organization, allBranches: allBranches, includeSubgroups: includeSubgroups}, nil + + return &GitlabProvider{client: client, organization: organization, allBranches: allBranches, includeSubgroups: includeSubgroups, includeSharedProjects: includeSharedProjects, topic: topic}, nil } func (g *GitlabProvider) GetBranches(ctx context.Context, repo *Repository) ([]*Repository, error) { @@ -64,8 +77,11 @@ func (g *GitlabProvider) GetBranches(ctx context.Context, repo *Repository) ([]* func (g *GitlabProvider) ListRepos(ctx context.Context, cloneProtocol string) ([]*Repository, error) { opt := &gitlab.ListGroupProjectsOptions{ ListOptions: gitlab.ListOptions{PerPage: 100}, - IncludeSubgroups: &g.includeSubgroups, + IncludeSubGroups: &g.includeSubgroups, + WithShared: &g.includeSharedProjects, + Topic: &g.topic, } + repos := []*Repository{} for { gitlabRepos, resp, err := g.client.Groups.ListGroupProjects(g.organization, opt) @@ -84,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, }) } @@ -144,7 +168,11 @@ func (g *GitlabProvider) listBranches(_ context.Context, repo *Repository) ([]gi branches := []gitlab.Branch{} // If we don't specifically want to query for all branches, just use the default branch and call it a day. if !g.allBranches { - gitlabBranch, _, err := g.client.Branches.GetBranch(repo.RepositoryId, repo.Branch, nil) + gitlabBranch, resp, err := g.client.Branches.GetBranch(repo.RepositoryId, repo.Branch, nil) + // 404s are not an error here, just a normal false. + if resp != nil && resp.StatusCode == http.StatusNotFound { + return []gitlab.Branch{}, nil + } if err != nil { return nil, err } @@ -157,6 +185,10 @@ func (g *GitlabProvider) listBranches(_ context.Context, repo *Repository) ([]gi } for { gitlabBranches, resp, err := g.client.Branches.ListBranches(repo.RepositoryId, opt) + // 404s are not an error here, just a normal false. + if resp != nil && resp.StatusCode == http.StatusNotFound { + return []gitlab.Branch{}, nil + } if err != nil { return nil, err } diff --git a/applicationset/services/scm_provider/gitlab_test.go b/applicationset/services/scm_provider/gitlab_test.go index 272eab17c94da..b93616fa8367f 100644 --- a/applicationset/services/scm_provider/gitlab_test.go +++ b/applicationset/services/scm_provider/gitlab_test.go @@ -19,7 +19,7 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) { switch r.RequestURI { case "/api/v4": fmt.Println("here1") - case "/api/v4/groups/test-argocd-proton/projects?include_subgroups=false&per_page=100": + case "/api/v4/groups/test-argocd-proton/projects?include_subgroups=false&per_page=100", "/api/v4/groups/test-argocd-proton/projects?include_subgroups=false&per_page=100&topic=&with_shared=false": fmt.Println("here") _, err := io.WriteString(w, `[{ "id": 27084533, @@ -30,8 +30,12 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) { "path_with_namespace": "test-argocd-proton/argocd", "created_at": "2021-06-01T17:30:44.724Z", "default_branch": "master", - "tag_list": [], - "topics": [], + "tag_list": [ + "test-topic" + ], + "topics": [ + "test-topic" + ], "ssh_url_to_repo": "git@gitlab.com:test-argocd-proton/argocd.git", "http_url_to_repo": "https://gitlab.com/test-argocd-proton/argocd.git", "web_url": "https://gitlab.com/test-argocd-proton/argocd", @@ -143,6 +147,650 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) { if err != nil { t.Fail() } + case "/api/v4/groups/test-argocd-proton/projects?include_subgroups=true&per_page=100&topic=&with_shared=false": + fmt.Println("here") + _, err := io.WriteString(w, `[{ + "id": 27084533, + "description": "", + "name": "argocd", + "name_with_namespace": "test argocd proton / argocd", + "path": "argocd", + "path_with_namespace": "test-argocd-proton/argocd", + "created_at": "2021-06-01T17:30:44.724Z", + "default_branch": "master", + "tag_list": [ + "test-topic", + "specific-topic" + ], + "topics": [ + "test-topic", + "specific-topic" + ], + "ssh_url_to_repo": "git@gitlab.com:test-argocd-proton/argocd.git", + "http_url_to_repo": "https://gitlab.com/test-argocd-proton/argocd.git", + "web_url": "https://gitlab.com/test-argocd-proton/argocd", + "readme_url": null, + "avatar_url": null, + "forks_count": 0, + "star_count": 0, + "last_activity_at": "2021-06-04T08:19:51.656Z", + "namespace": { + "id": 12258515, + "name": "test argocd proton", + "path": "test-argocd-proton", + "kind": "gro* Connection #0 to host gitlab.com left intact up ", + "full_path ": "test - argocd - proton ", + "parent_id ": null, + "avatar_url ": null, + "web_url ": "https: //gitlab.com/groups/test-argocd-proton" + }, + "container_registry_image_prefix": "registry.gitlab.com/test-argocd-proton/argocd", + "_links": { + "self": "https://gitlab.com/api/v4/projects/27084533", + "issues": "https://gitlab.com/api/v4/projects/27084533/issues", + "merge_requests": "https://gitlab.com/api/v4/projects/27084533/merge_requests", + "repo_branches": "https://gitlab.com/api/v4/projects/27084533/repository/branches", + "labels": "https://gitlab.com/api/v4/projects/27084533/labels", + "events": "https://gitlab.com/api/v4/projects/27084533/events", + "members": "https://gitlab.com/api/v4/projects/27084533/members", + "cluster_agents": "https://gitlab.com/api/v4/projects/27084533/cluster_agents" + }, + "packages_enabled": true, + "empty_repo": false, + "archived": false, + "visibility": "public", + "resolve_outdated_diff_discussions": false, + "container_expiration_policy": { + "cadence": "1d", + "enabled": false, + "keep_n": 10, + "older_than": "90d", + "name_regex": ".*", + "name_regex_keep": null, + "next_run_at": "2021-06-02T17:30:44.740Z" + }, + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "jobs_enabled": true, + "snippets_enabled": true, + "container_registry_enabled": true, + "service_desk_enabled": true, + "can_create_merge_request_in": false, + "issues_access_level": "enabled", + "repository_access_level": "enabled", + "merge_requests_access_level": "enabled", + "forking_access_level": "enabled", + "wiki_access_level": "enabled", + "builds_access_level": "enabled", + "snippets_access_level": "enabled", + "pages_access_level": "enabled", + "operations_access_level": "enabled", + "analytics_access_level": "enabled", + "container_registry_access_level": "enabled", + "security_and_compliance_access_level": "private", + "emails_disabled": null, + "shared_runners_enabled": true, + "lfs_enabled": true, + "creator_id": 2378866, + "import_status": "none", + "open_issues_count": 0, + "ci_default_git_depth": 50, + "ci_forward_deployment_enabled": true, + "ci_job_token_scope_enabled": false, + "public_jobs": true, + "build_timeout": 3600, + "auto_cancel_pending_pipelines": "enabled", + "ci_config_path": "", + "shared_with_groups": [], + "only_allow_merge_if_pipeline_succeeds": false, + "allow_merge_on_skipped_pipeline": null, + "restrict_user_defined_variables": false, + "request_access_enabled": true, + "only_allow_merge_if_all_discussions_are_resolved": false, + "remove_source_branch_after_merge": true, + "printing_merge_request_link_enabled": true, + "merge_method": "merge", + "squash_option": "default_off", + "suggestion_commit_message": null, + "merge_commit_template": null, + "squash_commit_template": null, + "auto_devops_enabled": false, + "auto_devops_deploy_strategy": "continuous", + "autoclose_referenced_issues": true, + "keep_latest_artifact": true, + "runner_token_expiration_interval": null, + "approvals_before_merge": 0, + "mirror": false, + "external_authorization_classification_label": "", + "marked_for_deletion_at": null, + "marked_for_deletion_on": null, + "requirements_enabled": true, + "requirements_access_level": "enabled", + "security_and_compliance_enabled": false, + "compliance_frameworks": [], + "issues_template": null, + "merge_requests_template": null, + "merge_pipelines_enabled": false, + "merge_trains_enabled": false + }, + { + "id": 27084538, + "description": "This is a Project from a Subgroup", + "name": "argocd-subgroup", + "name_with_namespace": "test argocd proton / subgroup / argocd-subgroup", + "path": "argocd-subgroup", + "path_with_namespace": "test-argocd-proton/subgroup/argocd-subgroup", + "created_at": "2021-06-01T17:30:44.724Z", + "default_branch": "master", + "tag_list": [ + "test-topic" + ], + "topics": [ + "test-topic" + ], + "ssh_url_to_repo": "git@gitlab.com:test-argocd-proton/subgroup/argocd-subgroup.git", + "http_url_to_repo": "https://gitlab.com/test-argocd-proton/subgroup/argocd-subgroup.git", + "web_url": "https://gitlab.com/test-argocd-proton/subgroup/argocd-subgroup", + "readme_url": null, + "avatar_url": null, + "forks_count": 0, + "star_count": 0, + "last_activity_at": "2021-06-04T08:19:51.656Z", + "namespace": { + "id": 12258542, + "name": "subgroup", + "path": "subgroup", + "kind": "group ", + "full_path ": "test-argocd-proton/subgroup", + "parent_id ": 12258515, + "avatar_url ": null, + "web_url ": "https: //gitlab.com/groups/test-argocd-proton/subgroup" + }, + "container_registry_image_prefix": "registry.gitlab.com/test-argocd-proton/subgroup/argocd", + "_links": { + "self": "https://gitlab.com/api/v4/projects/27084538", + "issues": "https://gitlab.com/api/v4/projects/27084538/issues", + "merge_requests": "https://gitlab.com/api/v4/projects/27084538/merge_requests", + "repo_branches": "https://gitlab.com/api/v4/projects/27084538/repository/branches", + "labels": "https://gitlab.com/api/v4/projects/27084538/labels", + "events": "https://gitlab.com/api/v4/projects/27084538/events", + "members": "https://gitlab.com/api/v4/projects/27084538/members", + "cluster_agents": "https://gitlab.com/api/v4/projects/27084538/cluster_agents" + }, + "packages_enabled": true, + "empty_repo": false, + "archived": false, + "visibility": "public", + "resolve_outdated_diff_discussions": false, + "container_expiration_policy": { + "cadence": "1d", + "enabled": false, + "keep_n": 10, + "older_than": "90d", + "name_regex": ".*", + "name_regex_keep": null, + "next_run_at": "2021-06-02T17:30:44.740Z" + }, + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "jobs_enabled": true, + "snippets_enabled": true, + "container_registry_enabled": true, + "service_desk_enabled": true, + "can_create_merge_request_in": false, + "issues_access_level": "enabled", + "repository_access_level": "enabled", + "merge_requests_access_level": "enabled", + "forking_access_level": "enabled", + "wiki_access_level": "enabled", + "builds_access_level": "enabled", + "snippets_access_level": "enabled", + "pages_access_level": "enabled", + "operations_access_level": "enabled", + "analytics_access_level": "enabled", + "container_registry_access_level": "enabled", + "security_and_compliance_access_level": "private", + "emails_disabled": null, + "shared_runners_enabled": true, + "lfs_enabled": true, + "creator_id": 2378866, + "import_status": "none", + "open_issues_count": 0, + "ci_default_git_depth": 50, + "ci_forward_deployment_enabled": true, + "ci_job_token_scope_enabled": false, + "public_jobs": true, + "build_timeout": 3600, + "auto_cancel_pending_pipelines": "enabled", + "ci_config_path": "", + "shared_with_groups": [], + "only_allow_merge_if_pipeline_succeeds": false, + "allow_merge_on_skipped_pipeline": null, + "restrict_user_defined_variables": false, + "request_access_enabled": true, + "only_allow_merge_if_all_discussions_are_resolved": false, + "remove_source_branch_after_merge": true, + "printing_merge_request_link_enabled": true, + "merge_method": "merge", + "squash_option": "default_off", + "suggestion_commit_message": null, + "merge_commit_template": null, + "squash_commit_template": null, + "auto_devops_enabled": false, + "auto_devops_deploy_strategy": "continuous", + "autoclose_referenced_issues": true, + "keep_latest_artifact": true, + "runner_token_expiration_interval": null, + "approvals_before_merge": 0, + "mirror": false, + "external_authorization_classification_label": "", + "marked_for_deletion_at": null, + "marked_for_deletion_on": null, + "requirements_enabled": true, + "requirements_access_level": "enabled", + "security_and_compliance_enabled": false, + "compliance_frameworks": [], + "issues_template": null, + "merge_requests_template": null, + "merge_pipelines_enabled": false, + "merge_trains_enabled": false + } + ]`) + if err != nil { + t.Fail() + } + case "/api/v4/groups/test-argocd-proton/projects?include_subgroups=false&per_page=100&topic=specific-topic&with_shared=false": + fmt.Println("here") + _, err := io.WriteString(w, `[{ + "id": 27084533, + "description": "", + "name": "argocd", + "name_with_namespace": "test argocd proton / argocd", + "path": "argocd", + "path_with_namespace": "test-argocd-proton/argocd", + "created_at": "2021-06-01T17:30:44.724Z", + "default_branch": "master", + "tag_list": [ + "test-topic", + "specific-topic" + ], + "topics": [ + "test-topic", + "specific-topic" + ], + "ssh_url_to_repo": "git@gitlab.com:test-argocd-proton/argocd.git", + "http_url_to_repo": "https://gitlab.com/test-argocd-proton/argocd.git", + "web_url": "https://gitlab.com/test-argocd-proton/argocd", + "readme_url": null, + "avatar_url": null, + "forks_count": 0, + "star_count": 0, + "last_activity_at": "2021-06-04T08:19:51.656Z", + "namespace": { + "id": 12258515, + "name": "test argocd proton", + "path": "test-argocd-proton", + "kind": "gro* Connection #0 to host gitlab.com left intact up ", + "full_path ": "test - argocd - proton ", + "parent_id ": null, + "avatar_url ": null, + "web_url ": "https: //gitlab.com/groups/test-argocd-proton" + }, + "container_registry_image_prefix": "registry.gitlab.com/test-argocd-proton/argocd", + "_links": { + "self": "https://gitlab.com/api/v4/projects/27084533", + "issues": "https://gitlab.com/api/v4/projects/27084533/issues", + "merge_requests": "https://gitlab.com/api/v4/projects/27084533/merge_requests", + "repo_branches": "https://gitlab.com/api/v4/projects/27084533/repository/branches", + "labels": "https://gitlab.com/api/v4/projects/27084533/labels", + "events": "https://gitlab.com/api/v4/projects/27084533/events", + "members": "https://gitlab.com/api/v4/projects/27084533/members", + "cluster_agents": "https://gitlab.com/api/v4/projects/27084533/cluster_agents" + }, + "packages_enabled": true, + "empty_repo": false, + "archived": false, + "visibility": "public", + "resolve_outdated_diff_discussions": false, + "container_expiration_policy": { + "cadence": "1d", + "enabled": false, + "keep_n": 10, + "older_than": "90d", + "name_regex": ".*", + "name_regex_keep": null, + "next_run_at": "2021-06-02T17:30:44.740Z" + }, + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "jobs_enabled": true, + "snippets_enabled": true, + "container_registry_enabled": true, + "service_desk_enabled": true, + "can_create_merge_request_in": false, + "issues_access_level": "enabled", + "repository_access_level": "enabled", + "merge_requests_access_level": "enabled", + "forking_access_level": "enabled", + "wiki_access_level": "enabled", + "builds_access_level": "enabled", + "snippets_access_level": "enabled", + "pages_access_level": "enabled", + "operations_access_level": "enabled", + "analytics_access_level": "enabled", + "container_registry_access_level": "enabled", + "security_and_compliance_access_level": "private", + "emails_disabled": null, + "shared_runners_enabled": true, + "lfs_enabled": true, + "creator_id": 2378866, + "import_status": "none", + "open_issues_count": 0, + "ci_default_git_depth": 50, + "ci_forward_deployment_enabled": true, + "ci_job_token_scope_enabled": false, + "public_jobs": true, + "build_timeout": 3600, + "auto_cancel_pending_pipelines": "enabled", + "ci_config_path": "", + "shared_with_groups": [], + "only_allow_merge_if_pipeline_succeeds": false, + "allow_merge_on_skipped_pipeline": null, + "restrict_user_defined_variables": false, + "request_access_enabled": true, + "only_allow_merge_if_all_discussions_are_resolved": false, + "remove_source_branch_after_merge": true, + "printing_merge_request_link_enabled": true, + "merge_method": "merge", + "squash_option": "default_off", + "suggestion_commit_message": null, + "merge_commit_template": null, + "squash_commit_template": null, + "auto_devops_enabled": false, + "auto_devops_deploy_strategy": "continuous", + "autoclose_referenced_issues": true, + "keep_latest_artifact": true, + "runner_token_expiration_interval": null, + "approvals_before_merge": 0, + "mirror": false, + "external_authorization_classification_label": "", + "marked_for_deletion_at": null, + "marked_for_deletion_on": null, + "requirements_enabled": true, + "requirements_access_level": "enabled", + "security_and_compliance_enabled": false, + "compliance_frameworks": [], + "issues_template": null, + "merge_requests_template": null, + "merge_pipelines_enabled": false, + "merge_trains_enabled": false + } + ]`) + if err != nil { + t.Fail() + } + case "/api/v4/groups/test-argocd-proton/projects?include_subgroups=true&per_page=100&topic=&with_shared=true": + fmt.Println("here") + _, err := io.WriteString(w, `[{ + "id": 27084533, + "description": "", + "name": "argocd", + "name_with_namespace": "test argocd proton / argocd", + "path": "argocd", + "path_with_namespace": "test-argocd-proton/argocd", + "created_at": "2021-06-01T17:30:44.724Z", + "default_branch": "master", + "tag_list": [ + "test-topic" + ], + "topics": [ + "test-topic" + ], + "ssh_url_to_repo": "git@gitlab.com:test-argocd-proton/argocd.git", + "http_url_to_repo": "https://gitlab.com/test-argocd-proton/argocd.git", + "web_url": "https://gitlab.com/test-argocd-proton/argocd", + "readme_url": null, + "avatar_url": null, + "forks_count": 0, + "star_count": 0, + "last_activity_at": "2021-06-04T08:19:51.656Z", + "namespace": { + "id": 12258515, + "name": "test argocd proton", + "path": "test-argocd-proton", + "kind": "gro* Connection #0 to host gitlab.com left intact up ", + "full_path ": "test - argocd - proton ", + "parent_id ": null, + "avatar_url ": null, + "web_url ": "https: //gitlab.com/groups/test-argocd-proton" + }, + "container_registry_image_prefix": "registry.gitlab.com/test-argocd-proton/argocd", + "_links": { + "self": "https://gitlab.com/api/v4/projects/27084533", + "issues": "https://gitlab.com/api/v4/projects/27084533/issues", + "merge_requests": "https://gitlab.com/api/v4/projects/27084533/merge_requests", + "repo_branches": "https://gitlab.com/api/v4/projects/27084533/repository/branches", + "labels": "https://gitlab.com/api/v4/projects/27084533/labels", + "events": "https://gitlab.com/api/v4/projects/27084533/events", + "members": "https://gitlab.com/api/v4/projects/27084533/members", + "cluster_agents": "https://gitlab.com/api/v4/projects/27084533/cluster_agents" + }, + "packages_enabled": true, + "empty_repo": false, + "archived": false, + "visibility": "public", + "resolve_outdated_diff_discussions": false, + "container_expiration_policy": { + "cadence": "1d", + "enabled": false, + "keep_n": 10, + "older_than": "90d", + "name_regex": ".*", + "name_regex_keep": null, + "next_run_at": "2021-06-02T17:30:44.740Z" + }, + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "jobs_enabled": true, + "snippets_enabled": true, + "container_registry_enabled": true, + "service_desk_enabled": true, + "can_create_merge_request_in": false, + "issues_access_level": "enabled", + "repository_access_level": "enabled", + "merge_requests_access_level": "enabled", + "forking_access_level": "enabled", + "wiki_access_level": "enabled", + "builds_access_level": "enabled", + "snippets_access_level": "enabled", + "pages_access_level": "enabled", + "operations_access_level": "enabled", + "analytics_access_level": "enabled", + "container_registry_access_level": "enabled", + "security_and_compliance_access_level": "private", + "emails_disabled": null, + "shared_runners_enabled": true, + "lfs_enabled": true, + "creator_id": 2378866, + "import_status": "none", + "open_issues_count": 0, + "ci_default_git_depth": 50, + "ci_forward_deployment_enabled": true, + "ci_job_token_scope_enabled": false, + "public_jobs": true, + "build_timeout": 3600, + "auto_cancel_pending_pipelines": "enabled", + "ci_config_path": "", + "shared_with_groups": [], + "only_allow_merge_if_pipeline_succeeds": false, + "allow_merge_on_skipped_pipeline": null, + "restrict_user_defined_variables": false, + "request_access_enabled": true, + "only_allow_merge_if_all_discussions_are_resolved": false, + "remove_source_branch_after_merge": true, + "printing_merge_request_link_enabled": true, + "merge_method": "merge", + "squash_option": "default_off", + "suggestion_commit_message": null, + "merge_commit_template": null, + "squash_commit_template": null, + "auto_devops_enabled": false, + "auto_devops_deploy_strategy": "continuous", + "autoclose_referenced_issues": true, + "keep_latest_artifact": true, + "runner_token_expiration_interval": null, + "approvals_before_merge": 0, + "mirror": false, + "external_authorization_classification_label": "", + "marked_for_deletion_at": null, + "marked_for_deletion_on": null, + "requirements_enabled": true, + "requirements_access_level": "enabled", + "security_and_compliance_enabled": false, + "compliance_frameworks": [], + "issues_template": null, + "merge_requests_template": null, + "merge_pipelines_enabled": false, + "merge_trains_enabled": false + }, + { + "id": 27084534, + "description": "This is a Shared Project", + "name": "shared-argocd", + "name_with_namespace": "shared project to test argocd proton / argocd", + "path": "shared-argocd", + "path_with_namespace": "test-shared-argocd-proton/shared-argocd", + "created_at": "2021-06-11T17:30:44.724Z", + "default_branch": "master", + "tag_list": [ + "test-topic" + ], + "topics": [ + "test-topic" + ], + "ssh_url_to_repo": "git@gitlab.com:test-shared-argocd-proton/shared-argocd.git", + "http_url_to_repo": "https://gitlab.com/test-shared-argocd-proton/shared-argocd.git", + "web_url": "https://gitlab.com/test-shared-argocd-proton/shared-argocd", + "readme_url": null, + "avatar_url": null, + "forks_count": 0, + "star_count": 0, + "last_activity_at": "2021-06-04T08:19:51.656Z", + "namespace": { + "id": 12258518, + "name": "test shared argocd proton", + "path": "test-shared-argocd-proton", + "kind": "group", + "full_path ": "test-shared-argocd-proton", + "parent_id ": null, + "avatar_url ": null, + "web_url ": "https: //gitlab.com/groups/test-shared-argocd-proton" + }, + "container_registry_image_prefix": "registry.gitlab.com/test-shared-argocd-proton/shared-argocd", + "_links": { + "self": "https://gitlab.com/api/v4/projects/27084534", + "issues": "https://gitlab.com/api/v4/projects/27084534/issues", + "merge_requests": "https://gitlab.com/api/v4/projects/27084534/merge_requests", + "repo_branches": "https://gitlab.com/api/v4/projects/27084534/repository/branches", + "labels": "https://gitlab.com/api/v4/projects/27084534/labels", + "events": "https://gitlab.com/api/v4/projects/27084534/events", + "members": "https://gitlab.com/api/v4/projects/27084534/members", + "cluster_agents": "https://gitlab.com/api/v4/projects/27084534/cluster_agents" + }, + "packages_enabled": true, + "empty_repo": false, + "archived": false, + "visibility": "public", + "resolve_outdated_diff_discussions": false, + "container_expiration_policy": { + "cadence": "1d", + "enabled": false, + "keep_n": 10, + "older_than": "90d", + "name_regex": ".*", + "name_regex_keep": null, + "next_run_at": "2021-06-12T17:30:44.740Z" + }, + "issues_enabled": true, + "merge_requests_enabled": true, + "wiki_enabled": true, + "jobs_enabled": true, + "snippets_enabled": true, + "container_registry_enabled": true, + "service_desk_enabled": true, + "can_create_merge_request_in": false, + "issues_access_level": "enabled", + "repository_access_level": "enabled", + "merge_requests_access_level": "enabled", + "forking_access_level": "enabled", + "wiki_access_level": "enabled", + "builds_access_level": "enabled", + "snippets_access_level": "enabled", + "pages_access_level": "enabled", + "operations_access_level": "enabled", + "analytics_access_level": "enabled", + "container_registry_access_level": "enabled", + "security_and_compliance_access_level": "private", + "emails_disabled": null, + "shared_runners_enabled": true, + "lfs_enabled": true, + "creator_id": 2378866, + "import_status": "none", + "open_issues_count": 0, + "ci_default_git_depth": 50, + "ci_forward_deployment_enabled": true, + "ci_job_token_scope_enabled": false, + "public_jobs": true, + "build_timeout": 3600, + "auto_cancel_pending_pipelines": "enabled", + "ci_config_path": "", + "shared_with_groups": [ + { + "group_id": 12258515, + "group_name": "test-argocd-proton", + "group_full_path": "test-shared-argocd-proton", + "group_access_level": 30, + "expires_at": null + } + ], + "only_allow_merge_if_pipeline_succeeds": false, + "allow_merge_on_skipped_pipeline": null, + "restrict_user_defined_variables": false, + "request_access_enabled": true, + "only_allow_merge_if_all_discussions_are_resolved": false, + "remove_source_branch_after_merge": true, + "printing_merge_request_link_enabled": true, + "merge_method": "merge", + "squash_option": "default_off", + "suggestion_commit_message": null, + "merge_commit_template": null, + "squash_commit_template": null, + "auto_devops_enabled": false, + "auto_devops_deploy_strategy": "continuous", + "autoclose_referenced_issues": true, + "keep_latest_artifact": true, + "runner_token_expiration_interval": null, + "approvals_before_merge": 0, + "mirror": false, + "external_authorization_classification_label": "", + "marked_for_deletion_at": null, + "marked_for_deletion_on": null, + "requirements_enabled": true, + "requirements_access_level": "enabled", + "security_and_compliance_enabled": false, + "compliance_frameworks": [], + "issues_template": null, + "merge_requests_template": null, + "merge_pipelines_enabled": false, + "merge_trains_enabled": false + }]`) + if err != nil { + t.Fail() + } case "/api/v4/projects/27084533/repository/branches/master": fmt.Println("returning") _, err := io.WriteString(w, `{ @@ -229,6 +877,116 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) { if err != nil { t.Fail() } + case "/api/v4/projects/27084534/repository/branches?per_page=100": + _, err := io.WriteString(w, `[{ + "name": "master", + "commit": { + "id": "8898d7999fc99dd0fd578650b58b244fc63f6b53", + "short_id": "8898d799", + "created_at": "2021-06-04T08:24:44.000+00:00", + "parent_ids": null, + "title": "Merge branch 'pipeline-1317911429' into 'master'", + "message": "Merge branch 'pipeline-1317911429' into 'master'", + "author_name": "Martin Vozník", + "author_email": "martin@voznik.cz", + "authored_date": "2021-06-04T08:24:44.000+00:00", + "committer_name": "Martin Vozník", + "committer_email": "martin@voznik.cz", + "committed_date": "2021-06-04T08:24:44.000+00:00", + "trailers": null, + "web_url": "https://gitlab.com/test-shared-argocd-proton/shared-argocd/-/commit/8898d7999fc99dd0fd578650b58b244fc63f6b53" + }, + "merged": false, + "protected": true, + "developers_can_push": false, + "developers_can_merge": false, + "can_push": false, + "default": true, + "web_url": "https://gitlab.com/test-shared-argocd-proton/shared-argocd/-/tree/master" + }, { + "name": "pipeline-2310077506", + "commit": { + "id": "0f92540e5f396ba960adea4ed0aa905baf3f73d1", + "short_id": "0f92540e", + "created_at": "2021-06-01T18:39:59.000+00:00", + "parent_ids": null, + "title": "[testapp-ci] manifests/demo/test-app.yaml: release v1.0.1", + "message": "[testapp-ci] manifests/demo/test-app.yaml: release v1.0.1", + "author_name": "ci-test-app", + "author_email": "mvoznik+cicd@protonmail.com", + "authored_date": "2021-06-01T18:39:59.000+00:00", + "committer_name": "ci-test-app", + "committer_email": "mvoznik+cicd@protonmail.com", + "committed_date": "2021-06-01T18:39:59.000+00:00", + "trailers": null, + "web_url": "https://gitlab.com/test-shared-argocd-proton/shared-argocd/-/commit/0f92540e5f396ba960adea4ed0aa905baf3f73d1" + }, + "merged": false, + "protected": false, + "developers_can_push": false, + "developers_can_merge": false, + "can_push": false, + "default": false, + "web_url": "https://gitlab.com/test-shared-argocd-proton/shared-argocd/-/tree/pipeline-1310077506" + }]`) + if err != nil { + t.Fail() + } + case "/api/v4/projects/27084538/repository/branches?per_page=100": + _, err := io.WriteString(w, `[{ + "name": "master", + "commit": { + "id": "8898d7999fc99dd0fd578650b58b244fc63f6b58", + "short_id": "8898d801", + "created_at": "2021-06-04T08:24:44.000+00:00", + "parent_ids": null, + "title": "Merge branch 'pipeline-1317911429' into 'master'", + "message": "Merge branch 'pipeline-1317911429' into 'master'", + "author_name": "Martin Vozník", + "author_email": "martin@voznik.cz", + "authored_date": "2021-06-04T08:24:44.000+00:00", + "committer_name": "Martin Vozník", + "committer_email": "martin@voznik.cz", + "committed_date": "2021-06-04T08:24:44.000+00:00", + "trailers": null, + "web_url": "https://gitlab.com/test-argocd-proton/subgroup/argocd-subgroup/-/commit/8898d7999fc99dd0fd578650b58b244fc63f6b53" + }, + "merged": false, + "protected": true, + "developers_can_push": false, + "developers_can_merge": false, + "can_push": false, + "default": true, + "web_url": "https://gitlab.com/test-argocd-proton/subgroup/argocd-subgroup/-/tree/master" + }, { + "name": "pipeline-2310077506", + "commit": { + "id": "0f92540e5f396ba960adea4ed0aa905baf3f73d1", + "short_id": "0f92540e", + "created_at": "2021-06-01T18:39:59.000+00:00", + "parent_ids": null, + "title": "[testapp-ci] manifests/demo/test-app.yaml: release v1.0.1", + "message": "[testapp-ci] manifests/demo/test-app.yaml: release v1.0.1", + "author_name": "ci-test-app", + "author_email": "mvoznik+cicd@protonmail.com", + "authored_date": "2021-06-01T18:39:59.000+00:00", + "committer_name": "ci-test-app", + "committer_email": "mvoznik+cicd@protonmail.com", + "committed_date": "2021-06-01T18:39:59.000+00:00", + "trailers": null, + "web_url": "https://gitlab.com/test-argocd-proton/subgroup/argocd-subgroup/-/commit/0f92540e5f396ba960adea4ed0aa905baf3f73d1" + }, + "merged": false, + "protected": false, + "developers_can_push": false, + "developers_can_merge": false, + "can_push": false, + "default": false, + "web_url": "https://gitlab.com/test-argocd-proton/subgroup/argocd-subgroup/-/tree/pipeline-1310077506" + }]`) + if err != nil { + t.Fail() + } case "/api/v4/projects/test-argocd-proton%2Fargocd": fmt.Println("auct") _, err := io.WriteString(w, `{ @@ -240,8 +998,12 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) { "path_with_namespace": "test-argocd-proton/argocd", "created_at": "2021-06-01T17:30:44.724Z", "default_branch": "master", - "tag_list": [], - "topics": [], + "tag_list": [ + "test-topic" + ], + "topics": [ + "test-topic" + ], "ssh_url_to_repo": "git@gitlab.com:test-argocd-proton/argocd.git", "http_url_to_repo": "https://gitlab.com/test-argocd-proton/argocd.git", "web_url": "https://gitlab.com/test-argocd-proton/argocd", @@ -274,6 +1036,8 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) { if err != nil { t.Fail() } + case "/api/v4/projects/27084533/repository/branches/foo": + w.WriteHeader(http.StatusNotFound) default: _, err := io.WriteString(w, `[]`) if err != nil { @@ -284,10 +1048,10 @@ func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) { } func TestGitlabListRepos(t *testing.T) { cases := []struct { - name, proto, url string - hasError, allBranches, includeSubgroups bool - branches []string - filters []v1alpha1.SCMProviderGeneratorFilter + name, proto, url, topic string + hasError, allBranches, includeSubgroups, includeSharedProjects, insecure bool + branches []string + filters []v1alpha1.SCMProviderGeneratorFilter }{ { name: "blank protocol", @@ -299,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", @@ -315,32 +1089,66 @@ func TestGitlabListRepos(t *testing.T) { url: "git@gitlab.com:test-argocd-proton/argocd.git", branches: []string{"master"}, }, + { + name: "all subgroups", + allBranches: true, + url: "git@gitlab.com:test-argocd-proton/argocd.git", + branches: []string{"master"}, + includeSharedProjects: false, + includeSubgroups: true, + }, + { + name: "all subgroups and shared projects", + allBranches: true, + url: "git@gitlab.com:test-argocd-proton/argocd.git", + branches: []string{"master"}, + includeSharedProjects: true, + includeSubgroups: true, + }, + { + name: "specific topic", + allBranches: true, + url: "git@gitlab.com:test-argocd-proton/argocd.git", + branches: []string{"master"}, + includeSubgroups: false, + topic: "specific-topic", + }, } ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gitlabMockHandler(t)(w, r) })) for _, c := range cases { t.Run(c.name, func(t *testing.T) { - provider, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, c.allBranches, c.includeSubgroups) + provider, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, c.allBranches, c.includeSubgroups, c.includeSharedProjects, c.insecure, "", c.topic) rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto) if c.hasError { assert.NotNil(t, err) } else { assert.Nil(t, err) - // Just check that this one project shows up. Not a great test but better thing nothing? + // Just check that this one project shows up. Not a great test but better than nothing? repos := []*Repository{} + uniqueRepos := map[string]int{} branches := []string{} for _, r := range rawRepos { if r.Repository == "argocd" { repos = append(repos, r) branches = append(branches, r.Branch) } + uniqueRepos[r.Repository]++ } assert.NotEmpty(t, repos) assert.Equal(t, c.url, repos[0].URL) for _, b := range c.branches { assert.Contains(t, branches, b) } + // In case of listing subgroups, validate the number of returned projects + if c.includeSubgroups || c.includeSharedProjects { + assert.Equal(t, 2, len(uniqueRepos)) + } + // In case we filter on the topic, ensure we got only one repo returned + if c.topic != "" { + assert.Equal(t, 1, len(uniqueRepos)) + } } }) } @@ -350,7 +1158,7 @@ func TestGitlabHasPath(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gitlabMockHandler(t)(w, r) })) - host, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, false, true) + host, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, false, true, true, false, "", "") repo := &Repository{ Organization: "test-argocd-proton", Repository: "argocd", @@ -391,3 +1199,29 @@ func TestGitlabHasPath(t *testing.T) { }) } } + +func TestGitlabGetBranches(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gitlabMockHandler(t)(w, r) + })) + host, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, false, true, true, false, "", "") + + repo := &Repository{ + RepositoryId: 27084533, + Branch: "master", + } + t.Run("branch exists", func(t *testing.T) { + repos, err := host.GetBranches(context.Background(), repo) + assert.Nil(t, err) + assert.Equal(t, repos[0].Branch, "master") + }) + + repo2 := &Repository{ + RepositoryId: 27084533, + Branch: "foo", + } + t.Run("unknown branch", func(t *testing.T) { + _, err := host.GetBranches(context.Background(), repo2) + assert.NoError(t, err) + }) +} diff --git a/applicationset/utils/clusterUtils.go b/applicationset/utils/clusterUtils.go index e06d7b39fac50..3b34a5a863dbd 100644 --- a/applicationset/utils/clusterUtils.go +++ b/applicationset/utils/clusterUtils.go @@ -50,10 +50,10 @@ const ( // ValidateDestination checks: // if we used destination name we infer the server url // if we used both name and server then we return an invalid spec error -func ValidateDestination(ctx context.Context, dest *appv1.ApplicationDestination, clientset kubernetes.Interface, namespace string) error { +func ValidateDestination(ctx context.Context, dest *appv1.ApplicationDestination, clientset kubernetes.Interface, argoCDNamespace string) error { if dest.Name != "" { if dest.Server == "" { - server, err := getDestinationServer(ctx, dest.Name, clientset, namespace) + server, err := getDestinationServer(ctx, dest.Name, clientset, argoCDNamespace) if err != nil { return fmt.Errorf("unable to find destination server: %v", err) } @@ -70,11 +70,11 @@ func ValidateDestination(ctx context.Context, dest *appv1.ApplicationDestination return nil } -func getDestinationServer(ctx context.Context, clusterName string, clientset kubernetes.Interface, namespace string) (string, error) { +func getDestinationServer(ctx context.Context, clusterName string, clientset kubernetes.Interface, argoCDNamespace string) (string, error) { // settingsMgr := settings.NewSettingsManager(context.TODO(), clientset, namespace) // argoDB := db.NewDB(namespace, settingsMgr, clientset) // clusterList, err := argoDB.ListClusters(ctx) - clusterList, err := ListClusters(ctx, clientset, namespace) + clusterList, err := ListClusters(ctx, clientset, argoCDNamespace) if err != nil { return "", err } @@ -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/clusterUtils_test.go b/applicationset/utils/clusterUtils_test.go index ba5d24d1604f6..70332afdd80fb 100644 --- a/applicationset/utils/clusterUtils_test.go +++ b/applicationset/utils/clusterUtils_test.go @@ -13,7 +13,6 @@ import ( kubetesting "k8s.io/client-go/testing" argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets/utils" ) const ( @@ -69,7 +68,7 @@ func createClusterSecret(secretName string, clusterName string, clusterServer st secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: secretName, - Namespace: utils.ArgoCDNamespace, + Namespace: fakeNamespace, Labels: map[string]string{ ArgoCDSecretTypeLabel: ArgoCDSecretTypeCluster, }, @@ -111,7 +110,7 @@ func TestValidateDestination(t *testing.T) { objects = append(objects, secret) kubeclientset := fake.NewSimpleClientset(objects...) - appCond := ValidateDestination(context.Background(), &dest, kubeclientset, utils.ArgoCDNamespace) + appCond := ValidateDestination(context.Background(), &dest, kubeclientset, fakeNamespace) assert.Nil(t, appCond) assert.Equal(t, "https://127.0.0.1:6443", dest.Server) assert.True(t, dest.IsServerInferred()) @@ -124,7 +123,7 @@ func TestValidateDestination(t *testing.T) { Namespace: "default", } - err := ValidateDestination(context.Background(), &dest, nil, utils.ArgoCDNamespace) + err := ValidateDestination(context.Background(), &dest, nil, fakeNamespace) assert.Equal(t, "application destination can't have both name and server defined: minikube https://127.0.0.1:6443", err.Error()) assert.False(t, dest.IsServerInferred()) }) @@ -139,7 +138,7 @@ func TestValidateDestination(t *testing.T) { return true, nil, fmt.Errorf("an error occurred") }) - err := ValidateDestination(context.Background(), &dest, kubeclientset, utils.ArgoCDNamespace) + err := ValidateDestination(context.Background(), &dest, kubeclientset, fakeNamespace) assert.Equal(t, "unable to find destination server: an error occurred", err.Error()) assert.False(t, dest.IsServerInferred()) }) @@ -154,7 +153,7 @@ func TestValidateDestination(t *testing.T) { objects = append(objects, secret) kubeclientset := fake.NewSimpleClientset(objects...) - err := ValidateDestination(context.Background(), &dest, kubeclientset, utils.ArgoCDNamespace) + err := ValidateDestination(context.Background(), &dest, kubeclientset, fakeNamespace) assert.Equal(t, "unable to find destination server: there are no clusters with this name: minikube", err.Error()) assert.False(t, dest.IsServerInferred()) }) @@ -171,7 +170,7 @@ func TestValidateDestination(t *testing.T) { objects = append(objects, secret, secret2) kubeclientset := fake.NewSimpleClientset(objects...) - err := ValidateDestination(context.Background(), &dest, kubeclientset, utils.ArgoCDNamespace) + err := ValidateDestination(context.Background(), &dest, kubeclientset, fakeNamespace) assert.Equal(t, "unable to find destination server: there are 2 clusters with the same name: [https://127.0.0.1:2443 https://127.0.0.1:8443]", err.Error()) assert.False(t, dest.IsServerInferred()) }) diff --git a/applicationset/utils/createOrUpdate.go b/applicationset/utils/createOrUpdate.go index a9775eb7994c5..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,11 +51,24 @@ func CreateOrUpdate(ctx context.Context, c client.Client, obj client.Object, f c return controllerutil.OperationResultCreated, nil } - existing := obj.DeepCopyObject() + 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. @@ -75,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.Update(ctx, obj); 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 { @@ -95,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/policy.go b/applicationset/utils/policy.go index 926a50926cd05..a06509265a540 100644 --- a/applicationset/utils/policy.go +++ b/applicationset/utils/policy.go @@ -1,55 +1,22 @@ package utils -// Policy allows to apply different rules to a set of changes. -type Policy interface { - Update() bool - Delete() bool -} +import ( + argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" +) // Policies is a registry of available policies. -var Policies = map[string]Policy{ - "sync": &SyncPolicy{}, - "create-only": &CreateOnlyPolicy{}, - "create-update": &CreateUpdatePolicy{}, - "create-delete": &CreateDeletePolicy{}, -} - -type SyncPolicy struct{} - -func (p *SyncPolicy) Update() bool { - return true -} - -func (p *SyncPolicy) Delete() bool { - return true -} - -type CreateUpdatePolicy struct{} - -func (p *CreateUpdatePolicy) Update() bool { - return true -} - -func (p *CreateUpdatePolicy) Delete() bool { - return false -} - -type CreateOnlyPolicy struct{} - -func (p *CreateOnlyPolicy) Update() bool { - return false -} - -func (p *CreateOnlyPolicy) Delete() bool { - return false -} - -type CreateDeletePolicy struct{} - -func (p *CreateDeletePolicy) Update() bool { - return false -} - -func (p *CreateDeletePolicy) Delete() bool { - return true +var Policies = map[string]argov1alpha1.ApplicationsSyncPolicy{ + "create-only": argov1alpha1.ApplicationsSyncPolicyCreateOnly, + "create-update": argov1alpha1.ApplicationsSyncPolicyCreateUpdate, + "create-delete": argov1alpha1.ApplicationsSyncPolicyCreateDelete, + "sync": argov1alpha1.ApplicationsSyncPolicySync, + // Default is "sync" + "": argov1alpha1.ApplicationsSyncPolicySync, +} + +func DefaultPolicy(appSetSyncPolicy *argov1alpha1.ApplicationSetSyncPolicy, controllerPolicy argov1alpha1.ApplicationsSyncPolicy, enablePolicyOverride bool) argov1alpha1.ApplicationsSyncPolicy { + if appSetSyncPolicy == nil || appSetSyncPolicy.ApplicationsSync == nil || !enablePolicyOverride { + return controllerPolicy + } + return *appSetSyncPolicy.ApplicationsSync } diff --git a/applicationset/utils/selector.go b/applicationset/utils/selector.go new file mode 100644 index 0000000000000..53db73a5b3a48 --- /dev/null +++ b/applicationset/utils/selector.go @@ -0,0 +1,261 @@ +package utils + +import ( + "fmt" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/klog/v2" + "sort" + "strconv" + "strings" +) + +var ( + unaryOperators = []string{ + string(selection.Exists), string(selection.DoesNotExist), + } + binaryOperators = []string{ + string(selection.In), string(selection.NotIn), + string(selection.Equals), string(selection.DoubleEquals), string(selection.NotEquals), + string(selection.GreaterThan), string(selection.LessThan), + } + validRequirementOperators = append(binaryOperators, unaryOperators...) +) + +// Selector represents a label selector. +type Selector interface { + // Matches returns true if this selector matches the given set of labels. + Matches(labels.Labels) bool + + // Add adds requirements to the Selector + Add(r ...Requirement) Selector +} + +type internalSelector []Requirement + +// ByKey sorts requirements by key to obtain deterministic parser +type ByKey []Requirement + +func (a ByKey) Len() int { return len(a) } + +func (a ByKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +func (a ByKey) Less(i, j int) bool { return a[i].key < a[j].key } + +// Matches for a internalSelector returns true if all +// its Requirements match the input Labels. If any +// Requirement does not match, false is returned. +func (s internalSelector) Matches(l labels.Labels) bool { + for ix := range s { + if matches := s[ix].Matches(l); !matches { + return false + } + } + return true +} + +// Add adds requirements to the selector. It copies the current selector returning a new one +func (s internalSelector) Add(reqs ...Requirement) Selector { + ret := make(internalSelector, 0, len(s)+len(reqs)) + ret = append(ret, s...) + ret = append(ret, reqs...) + sort.Sort(ByKey(ret)) + return ret +} + +type nothingSelector struct{} + +func (n nothingSelector) Matches(l labels.Labels) bool { + return false +} + +func (n nothingSelector) Add(r ...Requirement) Selector { + return n +} + +// Nothing returns a selector that matches no labels +func nothing() Selector { + return nothingSelector{} +} + +// Everything returns a selector that matches all labels. +func everything() Selector { + return internalSelector{} +} + +// LabelSelectorAsSelector converts the LabelSelector api type into a struct that implements +// labels.Selector +// Note: This function should be kept in sync with the selector methods in pkg/labels/selector.go +func LabelSelectorAsSelector(ps *v1.LabelSelector) (Selector, error) { + if ps == nil { + return nothing(), nil + } + if len(ps.MatchLabels)+len(ps.MatchExpressions) == 0 { + return everything(), nil + } + requirements := make([]Requirement, 0, len(ps.MatchLabels)+len(ps.MatchExpressions)) + for k, v := range ps.MatchLabels { + r, err := newRequirement(k, selection.Equals, []string{v}) + if err != nil { + return nil, err + } + requirements = append(requirements, *r) + } + for _, expr := range ps.MatchExpressions { + var op selection.Operator + switch expr.Operator { + case v1.LabelSelectorOpIn: + op = selection.In + case v1.LabelSelectorOpNotIn: + op = selection.NotIn + case v1.LabelSelectorOpExists: + op = selection.Exists + case v1.LabelSelectorOpDoesNotExist: + op = selection.DoesNotExist + default: + return nil, fmt.Errorf("%q is not a valid pod selector operator", expr.Operator) + } + r, err := newRequirement(expr.Key, op, append([]string(nil), expr.Values...)) + if err != nil { + return nil, err + } + requirements = append(requirements, *r) + } + selector := newSelector() + selector = selector.Add(requirements...) + return selector, nil +} + +// NewSelector returns a nil selector +func newSelector() Selector { + return internalSelector(nil) +} + +func validateLabelKey(k string, path *field.Path) *field.Error { + if errs := validation.IsQualifiedName(k); len(errs) != 0 { + return field.Invalid(path, k, strings.Join(errs, "; ")) + } + return nil +} + +// NewRequirement is the constructor for a Requirement. +// If any of these rules is violated, an error is returned: +// (1) The operator can only be In, NotIn, Equals, DoubleEquals, Gt, Lt, NotEquals, Exists, or DoesNotExist. +// (2) If the operator is In or NotIn, the values set must be non-empty. +// (3) If the operator is Equals, DoubleEquals, or NotEquals, the values set must contain one value. +// (4) If the operator is Exists or DoesNotExist, the value set must be empty. +// (5) If the operator is Gt or Lt, the values set must contain only one value, which will be interpreted as an integer. +// (6) The key is invalid due to its length, or sequence +// +// of characters. See validateLabelKey for more details. +// +// The empty string is a valid value in the input values set. +// Returned error, if not nil, is guaranteed to be an aggregated field.ErrorList +func newRequirement(key string, op selection.Operator, vals []string, opts ...field.PathOption) (*Requirement, error) { + var allErrs field.ErrorList + path := field.ToPath(opts...) + if err := validateLabelKey(key, path.Child("key")); err != nil { + allErrs = append(allErrs, err) + } + + valuePath := path.Child("values") + switch op { + case selection.In, selection.NotIn: + if len(vals) == 0 { + allErrs = append(allErrs, field.Invalid(valuePath, vals, "for 'in', 'notin' operators, values set can't be empty")) + } + case selection.Equals, selection.DoubleEquals, selection.NotEquals: + if len(vals) != 1 { + allErrs = append(allErrs, field.Invalid(valuePath, vals, "exact-match compatibility requires one single value")) + } + case selection.Exists, selection.DoesNotExist: + if len(vals) != 0 { + allErrs = append(allErrs, field.Invalid(valuePath, vals, "values set must be empty for exists and does not exist")) + } + case selection.GreaterThan, selection.LessThan: + if len(vals) != 1 { + allErrs = append(allErrs, field.Invalid(valuePath, vals, "for 'Gt', 'Lt' operators, exactly one value is required")) + } + for i := range vals { + if _, err := strconv.ParseInt(vals[i], 10, 64); err != nil { + allErrs = append(allErrs, field.Invalid(valuePath.Index(i), vals[i], "for 'Gt', 'Lt' operators, the value must be an integer")) + } + } + default: + allErrs = append(allErrs, field.NotSupported(path.Child("operator"), op, validRequirementOperators)) + } + + return &Requirement{key: key, operator: op, strValues: vals}, allErrs.ToAggregate() +} + +// Requirement contains values, a key, and an operator that relates the key and values. +// The zero value of Requirement is invalid. +// Requirement implements both set based match and exact match +// Requirement should be initialized via NewRequirement constructor for creating a valid Requirement. +// +k8s:deepcopy-gen=true +type Requirement struct { + key string + operator selection.Operator + // In the majority of cases we have at most one value here. + // It is generally faster to operate on a single-element slice + // than on a single-element map, so we have a slice here. + strValues []string +} + +func (r *Requirement) hasValue(value string) bool { + for i := range r.strValues { + if r.strValues[i] == value { + return true + } + } + return false +} + +func (r *Requirement) Matches(ls labels.Labels) bool { + switch r.operator { + case selection.In, selection.Equals, selection.DoubleEquals: + if !ls.Has(r.key) { + return false + } + return r.hasValue(ls.Get(r.key)) + case selection.NotIn, selection.NotEquals: + if !ls.Has(r.key) { + return true + } + return !r.hasValue(ls.Get(r.key)) + case selection.Exists: + return ls.Has(r.key) + case selection.DoesNotExist: + return !ls.Has(r.key) + case selection.GreaterThan, selection.LessThan: + if !ls.Has(r.key) { + return false + } + lsValue, err := strconv.ParseInt(ls.Get(r.key), 10, 64) + if err != nil { + klog.V(10).Infof("ParseInt failed for value %+v in label %+v, %+v", ls.Get(r.key), ls, err) + return false + } + + // There should be only one strValue in r.strValues, and can be converted to an integer. + if len(r.strValues) != 1 { + klog.V(10).Infof("Invalid values count %+v of requirement %#v, for 'Gt', 'Lt' operators, exactly one value is required", len(r.strValues), r) + return false + } + + var rValue int64 + for i := range r.strValues { + rValue, err = strconv.ParseInt(r.strValues[i], 10, 64) + if err != nil { + klog.V(10).Infof("ParseInt failed for value %+v in requirement %#v, for 'Gt', 'Lt' operators, the value must be an integer", r.strValues[i], r) + return false + } + } + return (r.operator == selection.GreaterThan && lsValue > rValue) || (r.operator == selection.LessThan && lsValue < rValue) + default: + return false + } +} diff --git a/applicationset/utils/template_functions.go b/applicationset/utils/template_functions.go new file mode 100644 index 0000000000000..84ab870404f1a --- /dev/null +++ b/applicationset/utils/template_functions.go @@ -0,0 +1,71 @@ +package utils + +import ( + "regexp" + "strings" + + "sigs.k8s.io/yaml" +) + +// SanitizeName sanitizes the name in accordance with the below rules +// 1. contain no more than 253 characters +// 2. contain only lowercase alphanumeric characters, '-' or '.' +// 3. start and end with an alphanumeric character +func SanitizeName(name string) string { + invalidDNSNameChars := regexp.MustCompile("[^-a-z0-9.]") + maxDNSNameLength := 253 + + name = strings.ToLower(name) + name = invalidDNSNameChars.ReplaceAllString(name, "-") + if len(name) > maxDNSNameLength { + name = name[:maxDNSNameLength] + } + + return strings.Trim(name, "-.") +} + +// This has been copied from helm and may be removed as soon as it is retrofited in sprig +// toYAML takes an interface, marshals it to yaml, and returns a string. It will +// always return a string, even on marshal error (empty string). +// +// This is designed to be called from a template. +func toYAML(v interface{}) (string, error) { + data, err := yaml.Marshal(v) + if err != nil { + // Swallow errors inside of a template. + return "", err + } + return strings.TrimSuffix(string(data), "\n"), nil +} + +// This has been copied from helm and may be removed as soon as it is retrofited in sprig +// fromYAML converts a YAML document into a map[string]interface{}. +// +// This is not a general-purpose YAML parser, and will not parse all valid +// YAML documents. Additionally, because its intended use is within templates +// it tolerates errors. It will insert the returned error message string into +// m["Error"] in the returned map. +func fromYAML(str string) (map[string]interface{}, error) { + m := map[string]interface{}{} + + if err := yaml.Unmarshal([]byte(str), &m); err != nil { + return nil, err + } + return m, nil +} + +// This has been copied from helm and may be removed as soon as it is retrofited in sprig +// fromYAMLArray converts a YAML array into a []interface{}. +// +// This is not a general-purpose YAML parser, and will not parse all valid +// YAML documents. Additionally, because its intended use is within templates +// it tolerates errors. It will insert the returned error message string as +// the first and only item in the returned array. +func fromYAMLArray(str string) ([]interface{}, error) { + a := []interface{}{} + + if err := yaml.Unmarshal([]byte(str), &a); err != nil { + return nil, err + } + return a, nil +} diff --git a/applicationset/utils/utils.go b/applicationset/utils/utils.go index 254478ee45c7f..2d128eb81a16c 100644 --- a/applicationset/utils/utils.go +++ b/applicationset/utils/utils.go @@ -2,9 +2,12 @@ package utils import ( "bytes" + "crypto/tls" + "crypto/x509" "encoding/json" "fmt" "io" + "os" "reflect" "regexp" "sort" @@ -13,7 +16,9 @@ import ( "unsafe" "github.com/Masterminds/sprig/v3" + "github.com/gosimple/slug" "github.com/valyala/fasttemplate" + "sigs.k8s.io/yaml" log "github.com/sirupsen/logrus" @@ -28,10 +33,15 @@ func init() { delete(sprigFuncMap, "expandenv") delete(sprigFuncMap, "getHostByName") sprigFuncMap["normalize"] = SanitizeName + sprigFuncMap["slugify"] = SlugifyName + sprigFuncMap["toYaml"] = toYAML + sprigFuncMap["fromYaml"] = fromYAML + sprigFuncMap["fromYamlArray"] = fromYAMLArray } type Renderer interface { - RenderTemplateParams(tmpl *argoappsv1.Application, syncPolicy *argoappsv1.ApplicationSetSyncPolicy, params map[string]interface{}, useGoTemplate bool) (*argoappsv1.Application, error) + 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 { @@ -48,9 +58,25 @@ func copyUnexported(copy, original reflect.Value) { copyValueIntoUnexported(copy, unexported) } +func IsJSONStr(str string) bool { + str = strings.TrimSpace(str) + return len(str) > 0 && str[0] == '{' +} + +func ConvertYAMLToJSON(str string) (string, error) { + if !IsJSONStr(str) { + jsonStr, err := yaml.YAMLToJSON([]byte(str)) + if err != nil { + return str, err + } + return string(jsonStr), nil + } + return str, nil +} + // This function is in charge of searching all String fields of the object recursively and apply templating // thanks to https://gist.github.com/randallmlough/1fd78ec8a1034916ca52281e3b886dc7 -func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[string]interface{}, useGoTemplate bool) error { +func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) error { switch original.Kind() { // The first cases handle nested structures and translate them recursively // If it is a pointer we need to unwrap and call once again @@ -70,7 +96,8 @@ func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[stri copyUnexported(copy, original) } // Unwrap the newly created pointer - if err := r.deeplyReplace(copy.Elem(), originalValue, replaceMap, useGoTemplate); err != nil { + if err := r.deeplyReplace(copy.Elem(), originalValue, replaceMap, useGoTemplate, goTemplateOptions); err != nil { + // Not wrapping the error, since this is a recursive function. Avoids excessively long error messages. return err } @@ -83,11 +110,19 @@ func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[stri originalValue := original.Elem() // Create a new object. Now new gives us a pointer, but we want the value it // points to, so we have to call Elem() to unwrap it - copyValue := reflect.New(originalValue.Type()).Elem() - if err := r.deeplyReplace(copyValue, originalValue, replaceMap, useGoTemplate); err != nil { - return err + + if originalValue.IsValid() { + reflectType := originalValue.Type() + + reflectValue := reflect.New(reflectType) + + copyValue := reflectValue.Elem() + if err := r.deeplyReplace(copyValue, originalValue, replaceMap, useGoTemplate, goTemplateOptions); err != nil { + // Not wrapping the error, since this is a recursive function. Avoids excessively long error messages. + return err + } + copy.Set(copyValue) } - copy.Set(copyValue) // If it is a struct we translate each field case reflect.Struct: @@ -96,7 +131,31 @@ func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[stri // specific case time if currentType == "time.Time" { copy.Field(i).Set(original.Field(i)) - } else if err := r.deeplyReplace(copy.Field(i), original.Field(i), replaceMap, useGoTemplate); err != nil { + } else if currentType == "Raw.k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" || currentType == "Raw.k8s.io/apimachinery/pkg/runtime" { + var unmarshaled interface{} + originalBytes := original.Field(i).Bytes() + convertedToJson, err := ConvertYAMLToJSON(string(originalBytes)) + if err != nil { + return fmt.Errorf("error while converting template to json %q: %w", convertedToJson, err) + } + err = json.Unmarshal([]byte(convertedToJson), &unmarshaled) + if err != nil { + return fmt.Errorf("failed to unmarshal JSON field: %w", err) + } + jsonOriginal := reflect.ValueOf(&unmarshaled) + jsonCopy := reflect.New(jsonOriginal.Type()).Elem() + err = r.deeplyReplace(jsonCopy, jsonOriginal, replaceMap, useGoTemplate, goTemplateOptions) + if err != nil { + return fmt.Errorf("failed to deeply replace JSON field contents: %w", err) + } + jsonCopyInterface := jsonCopy.Interface().(*interface{}) + data, err := json.Marshal(jsonCopyInterface) + if err != nil { + return fmt.Errorf("failed to marshal templated JSON field: %w", err) + } + copy.Field(i).Set(reflect.ValueOf(data)) + } else if err := r.deeplyReplace(copy.Field(i), original.Field(i), replaceMap, useGoTemplate, goTemplateOptions); err != nil { + // Not wrapping the error, since this is a recursive function. Avoids excessively long error messages. return err } } @@ -110,7 +169,8 @@ func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[stri } for i := 0; i < original.Len(); i += 1 { - if err := r.deeplyReplace(copy.Index(i), original.Index(i), replaceMap, useGoTemplate); err != nil { + if err := r.deeplyReplace(copy.Index(i), original.Index(i), replaceMap, useGoTemplate, goTemplateOptions); err != nil { + // Not wrapping the error, since this is a recursive function. Avoids excessively long error messages. return err } } @@ -124,20 +184,22 @@ func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[stri } for _, key := range original.MapKeys() { originalValue := original.MapIndex(key) - if originalValue.Kind() != reflect.String && originalValue.IsNil() { + if originalValue.Kind() != reflect.String && isNillable(originalValue) && originalValue.IsNil() { continue } // New gives us a pointer, but again we want the value copyValue := reflect.New(originalValue.Type()).Elem() - if err := r.deeplyReplace(copyValue, originalValue, replaceMap, useGoTemplate); err != nil { + if err := r.deeplyReplace(copyValue, originalValue, replaceMap, useGoTemplate, goTemplateOptions); err != nil { + // Not wrapping the error, since this is a recursive function. Avoids excessively long error messages. return err } // Keys can be templated as well as values (e.g. to template something into an annotation). if key.Kind() == reflect.String { - templatedKey, err := r.Replace(key.String(), replaceMap, useGoTemplate) + templatedKey, err := r.Replace(key.String(), replaceMap, useGoTemplate, goTemplateOptions) if err != nil { + // Not wrapping the error, since this is a recursive function. Avoids excessively long error messages. return err } key = reflect.ValueOf(templatedKey) @@ -150,8 +212,9 @@ func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[stri // If it is a string translate it (yay finally we're doing what we came for) case reflect.String: strToTemplate := original.String() - templated, err := r.Replace(strToTemplate, replaceMap, useGoTemplate) + templated, err := r.Replace(strToTemplate, replaceMap, useGoTemplate, goTemplateOptions) if err != nil { + // Not wrapping the error, since this is a recursive function. Avoids excessively long error messages. return err } if copy.CanSet() { @@ -172,9 +235,19 @@ func (r *Render) deeplyReplace(copy, original reflect.Value, replaceMap map[stri return nil } -func (r *Render) RenderTemplateParams(tmpl *argoappsv1.Application, syncPolicy *argoappsv1.ApplicationSetSyncPolicy, params map[string]interface{}, useGoTemplate bool) (*argoappsv1.Application, error) { +// isNillable returns true if the value is something which may be set to nil. This function is meant to guard against a +// panic from calling IsNil on a non-pointer type. +func isNillable(v reflect.Value) bool { + switch v.Kind() { + case reflect.Map, reflect.Pointer, reflect.UnsafePointer, reflect.Interface, reflect.Slice: + return true + } + return false +} + +func (r *Render) RenderTemplateParams(tmpl *argoappsv1.Application, syncPolicy *argoappsv1.ApplicationSetSyncPolicy, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (*argoappsv1.Application, error) { if tmpl == nil { - return nil, fmt.Errorf("application template is empty ") + return nil, fmt.Errorf("application template is empty") } if len(params) == 0 { @@ -184,7 +257,7 @@ func (r *Render) RenderTemplateParams(tmpl *argoappsv1.Application, syncPolicy * original := reflect.ValueOf(tmpl) copy := reflect.New(original.Type()).Elem() - if err := r.deeplyReplace(copy, original, params, useGoTemplate); err != nil { + if err := r.deeplyReplace(copy, original, params, useGoTemplate, goTemplateOptions); err != nil { return nil, err } @@ -204,16 +277,40 @@ func (r *Render) RenderTemplateParams(tmpl *argoappsv1.Application, syncPolicy * return replacedTmpl, nil } +func (r *Render) RenderGeneratorParams(gen *argoappsv1.ApplicationSetGenerator, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (*argoappsv1.ApplicationSetGenerator, error) { + if gen == nil { + return nil, fmt.Errorf("generator is empty") + } + + if len(params) == 0 { + return gen, nil + } + + original := reflect.ValueOf(gen) + copy := reflect.New(original.Type()).Elem() + + if err := r.deeplyReplace(copy, original, params, useGoTemplate, goTemplateOptions); err != nil { + return nil, fmt.Errorf("failed to replace parameters in generator: %w", err) + } + + replacedGen := copy.Interface().(*argoappsv1.ApplicationSetGenerator) + + return replacedGen, nil +} + var isTemplatedRegex = regexp.MustCompile(".*{{.*}}.*") // Replace executes basic string substitution of a template with replacement values. // remaining in the substituted template. -func (r *Render) Replace(tmpl string, replaceMap map[string]interface{}, useGoTemplate bool) (string, error) { +func (r *Render) Replace(tmpl string, replaceMap map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (string, error) { if useGoTemplate { template, err := template.New("").Funcs(sprigFuncMap).Parse(tmpl) if err != nil { return "", fmt.Errorf("failed to parse template %s: %w", tmpl, err) } + for _, option := range goTemplateOptions { + template = template.Option(option) + } var replacedTmplBuffer bytes.Buffer if err = template.Execute(&replacedTmplBuffer, replaceMap); err != nil { @@ -227,7 +324,10 @@ func (r *Render) Replace(tmpl string, replaceMap map[string]interface{}, useGoTe return tmpl, nil } - fstTmpl := fasttemplate.New(tmpl, "{{", "}}") + fstTmpl, err := fasttemplate.NewTemplate(tmpl, "{{", "}}") + if err != nil { + return "", fmt.Errorf("invalid template: %w", err) + } replacedTmpl := fstTmpl.ExecuteFuncString(func(w io.Writer, tag string) (int, error) { trimmedTag := strings.TrimSpace(tag) replacement, ok := replaceMap[trimmedTag].(string) @@ -337,19 +437,85 @@ func NormalizeBitbucketBasePath(basePath string) string { return basePath } -// SanitizeName sanitizes the name in accordance with the below rules -// 1. contain no more than 253 characters -// 2. contain only lowercase alphanumeric characters, '-' or '.' -// 3. start and end with an alphanumeric character -func SanitizeName(name string) string { - invalidDNSNameChars := regexp.MustCompile("[^-a-z0-9.]") - maxDNSNameLength := 253 - - name = strings.ToLower(name) - name = invalidDNSNameChars.ReplaceAllString(name, "-") - if len(name) > maxDNSNameLength { - name = name[:maxDNSNameLength] +// 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{} + + if scmRootCAPath != "" { + _, err := os.Stat(scmRootCAPath) + if os.IsNotExist(err) { + log.Errorf("scmRootCAPath '%s' specified does not exist: %s", scmRootCAPath, err) + return tlsConfig + } + rootCA, err := os.ReadFile(scmRootCAPath) + if err != nil { + log.Errorf("error reading certificate from file '%s', proceeding without custom rootCA : %s", scmRootCAPath, err) + return tlsConfig + } + certPool := x509.NewCertPool() + ok := certPool.AppendCertsFromPEM([]byte(rootCA)) + if !ok { + log.Errorf("failed to append certificates from PEM: proceeding without custom rootCA") + } else { + tlsConfig.RootCAs = certPool + } } + return tlsConfig +} + +func GetTlsConfig(scmRootCAPath string, insecure bool) *tls.Config { + tlsConfig := getTlsConfigWithCACert(scmRootCAPath) - return strings.Trim(name, "-.") + if insecure { + tlsConfig.InsecureSkipVerify = true + } + return tlsConfig } diff --git a/applicationset/utils/utils_test.go b/applicationset/utils/utils_test.go index af36c18a39dbb..3b4702bc35c3f 100644 --- a/applicationset/utils/utils_test.go +++ b/applicationset/utils/utils_test.go @@ -1,6 +1,10 @@ package utils import ( + "crypto/x509" + "encoding/json" + "os" + "path" "testing" "time" @@ -8,11 +12,11 @@ import ( logtest "github.com/sirupsen/logrus/hooks/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" - argoappsetv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" argoappsv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) @@ -174,7 +178,7 @@ func TestRenderTemplateParams(t *testing.T) { // Render the cloned application, into a new application render := Render{} - newApplication, err := render.RenderTemplateParams(application, nil, test.params, false) + newApplication, err := render.RenderTemplateParams(application, nil, test.params, false, nil) // Retrieve the value of the target field from the newApplication, then verify that // the target field has been templated into the expected value @@ -195,6 +199,113 @@ func TestRenderTemplateParams(t *testing.T) { } +func TestRenderHelmValuesObjectJson(t *testing.T) { + + params := map[string]interface{}{ + "test": "Hello world", + } + + application := &argoappsv1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{"annotation-key": "annotation-value", "annotation-key2": "annotation-value2"}, + Labels: map[string]string{"label-key": "label-value", "label-key2": "label-value2"}, + CreationTimestamp: metav1.NewTime(time.Now()), + UID: types.UID("d546da12-06b7-4f9a-8ea2-3adb16a20e2b"), + Name: "application-one", + Namespace: "default", + }, + Spec: argoappsv1.ApplicationSpec{ + Source: &argoappsv1.ApplicationSource{ + Path: "", + RepoURL: "", + TargetRevision: "", + Chart: "", + Helm: &argoappsv1.ApplicationSourceHelm{ + ValuesObject: &runtime.RawExtension{ + Raw: []byte(`{ + "some": { + "string": "{{.test}}" + } + }`), + }, + }, + }, + Destination: argoappsv1.ApplicationDestination{ + Server: "", + Namespace: "", + Name: "", + }, + Project: "", + }, + } + + // Render the cloned application, into a new application + render := Render{} + newApplication, err := render.RenderTemplateParams(application, nil, params, true, []string{}) + + assert.NoError(t, err) + assert.NotNil(t, newApplication) + + var unmarshaled interface{} + err = json.Unmarshal(newApplication.Spec.Source.Helm.ValuesObject.Raw, &unmarshaled) + + assert.NoError(t, err) + assert.Equal(t, unmarshaled.(map[string]interface{})["some"].(map[string]interface{})["string"], "Hello world") + +} + +func TestRenderHelmValuesObjectYaml(t *testing.T) { + + params := map[string]interface{}{ + "test": "Hello world", + } + + application := &argoappsv1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{"annotation-key": "annotation-value", "annotation-key2": "annotation-value2"}, + Labels: map[string]string{"label-key": "label-value", "label-key2": "label-value2"}, + CreationTimestamp: metav1.NewTime(time.Now()), + UID: types.UID("d546da12-06b7-4f9a-8ea2-3adb16a20e2b"), + Name: "application-one", + Namespace: "default", + }, + Spec: argoappsv1.ApplicationSpec{ + Source: &argoappsv1.ApplicationSource{ + Path: "", + RepoURL: "", + TargetRevision: "", + Chart: "", + Helm: &argoappsv1.ApplicationSourceHelm{ + ValuesObject: &runtime.RawExtension{ + Raw: []byte(`some: + string: "{{.test}}"`), + }, + }, + }, + Destination: argoappsv1.ApplicationDestination{ + Server: "", + Namespace: "", + Name: "", + }, + Project: "", + }, + } + + // Render the cloned application, into a new application + render := Render{} + newApplication, err := render.RenderTemplateParams(application, nil, params, true, []string{}) + + assert.NoError(t, err) + assert.NotNil(t, newApplication) + + var unmarshaled interface{} + err = json.Unmarshal(newApplication.Spec.Source.Helm.ValuesObject.Raw, &unmarshaled) + + assert.NoError(t, err) + assert.Equal(t, unmarshaled.(map[string]interface{})["some"].(map[string]interface{})["string"], "Hello world") + +} + func TestRenderTemplateParamsGoTemplate(t *testing.T) { // Believe it or not, this is actually less complex than the equivalent solution using reflection @@ -236,11 +347,12 @@ func TestRenderTemplateParamsGoTemplate(t *testing.T) { } tests := []struct { - name string - fieldVal string - params map[string]interface{} - expectedVal string - errorMessage string + name string + fieldVal string + params map[string]interface{} + expectedVal string + errorMessage string + templateOptions []string }{ { name: "simple substitution", @@ -423,6 +535,84 @@ func TestRenderTemplateParamsGoTemplate(t *testing.T) { }, errorMessage: `failed to execute go template {{.data.test}}: template: :1:7: executing "" at <.data.test>: can't evaluate field test in type interface {}`, }, + { + name: "lookup missing value with missingkey=default", + fieldVal: `--> {{.doesnotexist}} <--`, + expectedVal: `--> <--`, + params: map[string]interface{}{ + // if no params are passed then for some reason templating is skipped + "unused": "this is not used", + }, + }, + { + name: "lookup missing value with missingkey=error", + fieldVal: `--> {{.doesnotexist}} <--`, + expectedVal: "", + params: map[string]interface{}{ + // if no params are passed then for some reason templating is skipped + "unused": "this is not used", + }, + templateOptions: []string{"missingkey=error"}, + errorMessage: `failed to execute go template --> {{.doesnotexist}} <--: template: :1:6: executing "" at <.doesnotexist>: map has no entry for key "doesnotexist"`, + }, + { + name: "toYaml", + fieldVal: `{{ toYaml . | indent 2 }}`, + expectedVal: " foo:\n bar:\n bool: true\n number: 2\n str: Hello world", + params: map[string]interface{}{ + "foo": map[string]interface{}{ + "bar": map[string]interface{}{ + "bool": true, + "number": 2, + "str": "Hello world", + }, + }, + }, + }, + { + name: "toYaml Error", + fieldVal: `{{ toYaml . | indent 2 }}`, + expectedVal: " foo:\n bar:\n bool: true\n number: 2\n str: Hello world", + errorMessage: "failed to execute go template {{ toYaml . | indent 2 }}: template: :1:3: executing \"\" at : error calling toYaml: error marshaling into JSON: json: unsupported type: func(*string)", + params: map[string]interface{}{ + "foo": func(test *string) { + }, + }, + }, + { + name: "fromYaml", + fieldVal: `{{ get (fromYaml .value) "hello" }}`, + expectedVal: "world", + params: map[string]interface{}{ + "value": "hello: world", + }, + }, + { + name: "fromYaml error", + fieldVal: `{{ get (fromYaml .value) "hello" }}`, + expectedVal: "world", + errorMessage: "failed to execute go template {{ get (fromYaml .value) \"hello\" }}: template: :1:8: executing \"\" at : error calling fromYaml: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}", + params: map[string]interface{}{ + "value": "non\n compliant\n yaml", + }, + }, + { + name: "fromYamlArray", + fieldVal: `{{ fromYamlArray .value | last }}`, + expectedVal: "bonjour tout le monde", + params: map[string]interface{}{ + "value": "- hello world\n- bonjour tout le monde", + }, + }, + { + name: "fromYamlArray error", + fieldVal: `{{ fromYamlArray .value | last }}`, + expectedVal: "bonjour tout le monde", + errorMessage: "failed to execute go template {{ fromYamlArray .value | last }}: template: :1:3: executing \"\" at : error calling fromYamlArray: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type []interface {}", + params: map[string]interface{}{ + "value": "non\n compliant\n yaml", + }, + }, } for _, test := range tests { @@ -439,7 +629,7 @@ func TestRenderTemplateParamsGoTemplate(t *testing.T) { // Render the cloned application, into a new application render := Render{} - newApplication, err := render.RenderTemplateParams(application, nil, test.params, true) + newApplication, err := render.RenderTemplateParams(application, nil, test.params, true, test.templateOptions) // Retrieve the value of the target field from the newApplication, then verify that // the target field has been templated into the expected value @@ -464,6 +654,34 @@ func TestRenderTemplateParamsGoTemplate(t *testing.T) { } } +func TestRenderGeneratorParams_does_not_panic(t *testing.T) { + // This test verifies that the RenderGeneratorParams function does not panic when the value in a map is a non- + // nillable type. This is a regression test. + render := Render{} + params := map[string]interface{}{ + "branch": "master", + } + generator := &argoappsv1.ApplicationSetGenerator{ + Plugin: &argoappsv1.PluginGenerator{ + ConfigMapRef: argoappsv1.PluginConfigMapRef{ + Name: "cm-plugin", + }, + Input: argoappsv1.PluginInput{ + Parameters: map[string]apiextensionsv1.JSON{ + "branch": { + Raw: []byte(`"{{.branch}}"`), + }, + "repo": { + Raw: []byte(`"argo-test"`), + }, + }, + }, + }, + } + _, err := render.RenderGeneratorParams(generator, params, true, []string{}) + assert.NoError(t, err) +} + func TestRenderTemplateKeys(t *testing.T) { t.Run("fasttemplate", func(t *testing.T) { application := &argoappsv1.Application{ @@ -480,7 +698,7 @@ func TestRenderTemplateKeys(t *testing.T) { } render := Render{} - newApplication, err := render.RenderTemplateParams(application, nil, params, false) + newApplication, err := render.RenderTemplateParams(application, nil, params, false, nil) require.NoError(t, err) require.Contains(t, newApplication.ObjectMeta.Annotations, "annotation-some-key") assert.Equal(t, newApplication.ObjectMeta.Annotations["annotation-some-key"], "annotation-some-value") @@ -500,13 +718,21 @@ func TestRenderTemplateKeys(t *testing.T) { } render := Render{} - newApplication, err := render.RenderTemplateParams(application, nil, params, true) + newApplication, err := render.RenderTemplateParams(application, nil, params, true, nil) require.NoError(t, err) require.Contains(t, newApplication.ObjectMeta.Annotations, "annotation-some-key") assert.Equal(t, newApplication.ObjectMeta.Annotations["annotation-some-key"], "annotation-some-value") }) } +func Test_Render_Replace_no_panic_on_missing_closing_brace(t *testing.T) { + r := &Render{} + assert.NotPanics(t, func() { + _, err := r.Replace("{{properly.closed}} {{improperly.closed}", nil, false, []string{}) + assert.Error(t, err) + }) +} + func TestRenderTemplateParamsFinalizers(t *testing.T) { emptyApplication := &argoappsv1.Application{ @@ -528,7 +754,7 @@ func TestRenderTemplateParamsFinalizers(t *testing.T) { for _, c := range []struct { testName string - syncPolicy *argoappsetv1.ApplicationSetSyncPolicy + syncPolicy *argoappsv1.ApplicationSetSyncPolicy existingFinalizers []string expectedFinalizers []string }{ @@ -567,13 +793,13 @@ func TestRenderTemplateParamsFinalizers(t *testing.T) { { testName: "non-nil sync policy should use standard finalizer", existingFinalizers: nil, - syncPolicy: &argoappsetv1.ApplicationSetSyncPolicy{}, + syncPolicy: &argoappsv1.ApplicationSetSyncPolicy{}, expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, { testName: "preserveResourcesOnDeletion should not have a finalizer", existingFinalizers: nil, - syncPolicy: &argoappsetv1.ApplicationSetSyncPolicy{ + syncPolicy: &argoappsv1.ApplicationSetSyncPolicy{ PreserveResourcesOnDeletion: true, }, expectedFinalizers: nil, @@ -581,7 +807,7 @@ func TestRenderTemplateParamsFinalizers(t *testing.T) { { testName: "user-specified finalizer should overwrite preserveResourcesOnDeletion", existingFinalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, - syncPolicy: &argoappsetv1.ApplicationSetSyncPolicy{ + syncPolicy: &argoappsv1.ApplicationSetSyncPolicy{ PreserveResourcesOnDeletion: true, }, expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, @@ -601,7 +827,7 @@ func TestRenderTemplateParamsFinalizers(t *testing.T) { // Render the cloned application, into a new application render := Render{} - res, err := render.RenderTemplateParams(application, c.syncPolicy, params, true) + res, err := render.RenderTemplateParams(application, c.syncPolicy, params, true, nil) assert.Nil(t, err) assert.ElementsMatch(t, res.Finalizers, c.expectedFinalizers) @@ -615,27 +841,27 @@ func TestRenderTemplateParamsFinalizers(t *testing.T) { func TestCheckInvalidGenerators(t *testing.T) { scheme := runtime.NewScheme() - err := argoappsetv1.AddToScheme(scheme) + err := argoappsv1.AddToScheme(scheme) assert.Nil(t, err) err = argoappsv1.AddToScheme(scheme) assert.Nil(t, err) for _, c := range []struct { testName string - appSet argoappsetv1.ApplicationSet + appSet argoappsv1.ApplicationSet expectedMsg string }{ { testName: "invalid generator, without annotation", - appSet: argoappsetv1.ApplicationSet{ + appSet: argoappsv1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "test-app-set", Namespace: "namespace", }, - Spec: argoappsetv1.ApplicationSetSpec{ - Generators: []argoappsetv1.ApplicationSetGenerator{ + Spec: argoappsv1.ApplicationSetSpec{ + Generators: []argoappsv1.ApplicationSetGenerator{ { - List: &argoappsetv1.ListGenerator{}, + List: &argoappsv1.ListGenerator{}, Clusters: nil, Git: nil, }, @@ -647,7 +873,7 @@ func TestCheckInvalidGenerators(t *testing.T) { { List: nil, Clusters: nil, - Git: &argoappsetv1.GitGenerator{}, + Git: &argoappsv1.GitGenerator{}, }, }, }, @@ -656,7 +882,7 @@ func TestCheckInvalidGenerators(t *testing.T) { }, { testName: "invalid generator, with annotation", - appSet: argoappsetv1.ApplicationSet{ + appSet: argoappsv1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "test-app-set", Namespace: "namespace", @@ -673,10 +899,10 @@ func TestCheckInvalidGenerators(t *testing.T) { }`, }, }, - Spec: argoappsetv1.ApplicationSetSpec{ - Generators: []argoappsetv1.ApplicationSetGenerator{ + Spec: argoappsv1.ApplicationSetSpec{ + Generators: []argoappsv1.ApplicationSetGenerator{ { - List: &argoappsetv1.ListGenerator{}, + List: &argoappsv1.ListGenerator{}, Clusters: nil, Git: nil, }, @@ -688,7 +914,7 @@ func TestCheckInvalidGenerators(t *testing.T) { { List: nil, Clusters: nil, - Git: &argoappsetv1.GitGenerator{}, + Git: &argoappsv1.GitGenerator{}, }, { List: nil, @@ -719,20 +945,20 @@ func TestCheckInvalidGenerators(t *testing.T) { func TestInvalidGenerators(t *testing.T) { scheme := runtime.NewScheme() - err := argoappsetv1.AddToScheme(scheme) + err := argoappsv1.AddToScheme(scheme) assert.Nil(t, err) err = argoappsv1.AddToScheme(scheme) assert.Nil(t, err) for _, c := range []struct { testName string - appSet argoappsetv1.ApplicationSet + appSet argoappsv1.ApplicationSet expectedInvalid bool expectedNames map[string]bool }{ { testName: "valid generators, with annotation", - appSet: argoappsetv1.ApplicationSet{ + appSet: argoappsv1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", @@ -748,22 +974,22 @@ func TestInvalidGenerators(t *testing.T) { }`, }, }, - Spec: argoappsetv1.ApplicationSetSpec{ - Generators: []argoappsetv1.ApplicationSetGenerator{ + Spec: argoappsv1.ApplicationSetSpec{ + Generators: []argoappsv1.ApplicationSetGenerator{ { - List: &argoappsetv1.ListGenerator{}, + List: &argoappsv1.ListGenerator{}, Clusters: nil, Git: nil, }, { List: nil, - Clusters: &argoappsetv1.ClusterGenerator{}, + Clusters: &argoappsv1.ClusterGenerator{}, Git: nil, }, { List: nil, Clusters: nil, - Git: &argoappsetv1.GitGenerator{}, + Git: &argoappsv1.GitGenerator{}, }, }, }, @@ -773,13 +999,13 @@ func TestInvalidGenerators(t *testing.T) { }, { testName: "invalid generators, no annotation", - appSet: argoappsetv1.ApplicationSet{ + appSet: argoappsv1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argoappsetv1.ApplicationSetSpec{ - Generators: []argoappsetv1.ApplicationSetGenerator{ + Spec: argoappsv1.ApplicationSetSpec{ + Generators: []argoappsv1.ApplicationSetGenerator{ { List: nil, Clusters: nil, @@ -798,16 +1024,16 @@ func TestInvalidGenerators(t *testing.T) { }, { testName: "valid and invalid generators, no annotation", - appSet: argoappsetv1.ApplicationSet{ + appSet: argoappsv1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", }, - Spec: argoappsetv1.ApplicationSetSpec{ - Generators: []argoappsetv1.ApplicationSetGenerator{ + Spec: argoappsv1.ApplicationSetSpec{ + Generators: []argoappsv1.ApplicationSetGenerator{ { List: nil, - Clusters: &argoappsetv1.ClusterGenerator{}, + Clusters: &argoappsv1.ClusterGenerator{}, Git: nil, }, { @@ -818,7 +1044,7 @@ func TestInvalidGenerators(t *testing.T) { { List: nil, Clusters: nil, - Git: &argoappsetv1.GitGenerator{}, + Git: &argoappsv1.GitGenerator{}, }, }, }, @@ -828,7 +1054,7 @@ func TestInvalidGenerators(t *testing.T) { }, { testName: "valid and invalid generators, with annotation", - appSet: argoappsetv1.ApplicationSet{ + appSet: argoappsv1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", @@ -845,11 +1071,11 @@ func TestInvalidGenerators(t *testing.T) { }`, }, }, - Spec: argoappsetv1.ApplicationSetSpec{ - Generators: []argoappsetv1.ApplicationSetGenerator{ + Spec: argoappsv1.ApplicationSetSpec{ + Generators: []argoappsv1.ApplicationSetGenerator{ { List: nil, - Clusters: &argoappsetv1.ClusterGenerator{}, + Clusters: &argoappsv1.ClusterGenerator{}, Git: nil, }, { @@ -860,7 +1086,7 @@ func TestInvalidGenerators(t *testing.T) { { List: nil, Clusters: nil, - Git: &argoappsetv1.GitGenerator{}, + Git: &argoappsv1.GitGenerator{}, }, { List: nil, @@ -878,7 +1104,7 @@ func TestInvalidGenerators(t *testing.T) { }, { testName: "invalid generator, annotation with missing spec", - appSet: argoappsetv1.ApplicationSet{ + appSet: argoappsv1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", @@ -887,8 +1113,8 @@ func TestInvalidGenerators(t *testing.T) { }`, }, }, - Spec: argoappsetv1.ApplicationSetSpec{ - Generators: []argoappsetv1.ApplicationSetGenerator{ + Spec: argoappsv1.ApplicationSetSpec{ + Generators: []argoappsv1.ApplicationSetGenerator{ { List: nil, Clusters: nil, @@ -902,7 +1128,7 @@ func TestInvalidGenerators(t *testing.T) { }, { testName: "invalid generator, annotation with missing generators array", - appSet: argoappsetv1.ApplicationSet{ + appSet: argoappsv1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", @@ -913,8 +1139,8 @@ func TestInvalidGenerators(t *testing.T) { }`, }, }, - Spec: argoappsetv1.ApplicationSetSpec{ - Generators: []argoappsetv1.ApplicationSetGenerator{ + Spec: argoappsv1.ApplicationSetSpec{ + Generators: []argoappsv1.ApplicationSetGenerator{ { List: nil, Clusters: nil, @@ -928,7 +1154,7 @@ func TestInvalidGenerators(t *testing.T) { }, { testName: "invalid generator, annotation with empty generators array", - appSet: argoappsetv1.ApplicationSet{ + appSet: argoappsv1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", @@ -941,8 +1167,8 @@ func TestInvalidGenerators(t *testing.T) { }`, }, }, - Spec: argoappsetv1.ApplicationSetSpec{ - Generators: []argoappsetv1.ApplicationSetGenerator{ + Spec: argoappsv1.ApplicationSetSpec{ + Generators: []argoappsv1.ApplicationSetGenerator{ { List: nil, Clusters: nil, @@ -956,7 +1182,7 @@ func TestInvalidGenerators(t *testing.T) { }, { testName: "invalid generator, annotation with empty generator", - appSet: argoappsetv1.ApplicationSet{ + appSet: argoappsv1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", @@ -970,8 +1196,8 @@ func TestInvalidGenerators(t *testing.T) { }`, }, }, - Spec: argoappsetv1.ApplicationSetSpec{ - Generators: []argoappsetv1.ApplicationSetGenerator{ + Spec: argoappsv1.ApplicationSetSpec{ + Generators: []argoappsv1.ApplicationSetGenerator{ { List: nil, Clusters: nil, @@ -1016,3 +1242,129 @@ func TestNormalizeBitbucketBasePath(t *testing.T) { assert.Equal(t, c.expectedBasePath, result, c.testName) } } + +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) + + temppath := t.TempDir() + cert := ` +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIUGrTmW3qc39zqnE08e3qNDhUkeWswDQYJKoZIhvcNAQEL +BQAwbjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAklMMRAwDgYDVQQHDAdDaGljYWdv +MRQwEgYDVQQKDAtDYXBvbmUsIEluYzEQMA4GA1UECwwHU3BlY09wczEYMBYGA1UE +AwwPZm9vLmV4YW1wbGUuY29tMB4XDTE5MDcwODEzNTUwNVoXDTIwMDcwNzEzNTUw +NVowbjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAklMMRAwDgYDVQQHDAdDaGljYWdv +MRQwEgYDVQQKDAtDYXBvbmUsIEluYzEQMA4GA1UECwwHU3BlY09wczEYMBYGA1UE +AwwPZm9vLmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC +AgEA3csSO13w7qQXKeSLNcpeuAe6wAjXYbRkRl6ariqzTEDcFTKmy2QiXJTKoEGn +bvwxq0T91var7rxY88SGL/qi8Zmo0tVSR0XvKSKcghFIkQOTyDmVgMPZGCvixt4q +gQ7hUVSk4KkFmtcqBVuvnzI1d/DKfZAGKdmGcfRpuAsnVhac3swP0w4Tl1BFrK9U +vuIkz4KwXG77s5oB8rMUnyuLasLsGNpvpvXhkcQRhp6vpcCO2bS7kOTTelAPIucw +P37qkOEdZdiWCLrr57dmhg6tmcVlmBMg6JtmfLxn2HQd9ZrCKlkWxMk5NYs6CAW5 +kgbDZUWQTAsnHeoJKbcgtPkIbxDRxNpPukFMtbA4VEWv1EkODXy9FyEKDOI/PV6K +/80oLkgCIhCkP2mvwSFheU0RHTuZ0o0vVolP5TEOq5iufnDN4wrxqb12o//XLRc0 +RiLqGVVxhFdyKCjVxcLfII9AAp5Tse4PMh6bf6jDfB3OMvGkhMbJWhKXdR2NUTl0 +esKawMPRXIn5g3oBdNm8kyRsTTnvB567pU8uNSmA8j3jxfGCPynI8JdiwKQuW/+P +WgLIflgxqAfG85dVVOsFmF9o5o24dDslvv9yHnHH102c6ijPCg1EobqlyFzqqxOD +Wf2OPjIkzoTH+O27VRugnY/maIU1nshNO7ViRX5zIxEUtNMCAwEAAaNTMFEwHQYD +VR0OBBYEFNY4gDLgPBidogkmpO8nq5yAq5g+MB8GA1UdIwQYMBaAFNY4gDLgPBid +ogkmpO8nq5yAq5g+MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIB +AJ0WGioNtGNg3m6ywpmxNThorQD5ZvDMlmZlDVk78E2wfNyMhwbVhKhlAnONv0wv +kmsGjibY75nRZ+EK9PxSJ644841fryQXQ+bli5fhr7DW3uTKwaRsnzETJXRJuljq +6+c6Zyg1/mqwnyx7YvPgVh3w496DYx/jm6Fm1IEq3BzOmn6H/gGPq3gbURzEqI3h +P+kC2vJa8RZWrpa05Xk/Q1QUkErDX9vJghb9z3+GgirISZQzqWRghII/znv3NOE6 +zoIgaaWNFn8KPeBVpUoboH+IhpgibsnbTbI0G7AMtFq6qm3kn/4DZ2N2tuh1G2tT +zR2Fh7hJbU7CrqxANrgnIoHG/nLSvzE24ckLb0Vj69uGQlwnZkn9fz6F7KytU+Az +NoB2rjufaB0GQi1azdboMvdGSOxhSCAR8otWT5yDrywCqVnEvjw0oxKmuRduNe2/ +6AcG6TtK2/K+LHuhymiAwZM2qE6VD2odvb+tCzDkZOIeoIz/JcVlNpXE9FuVl250 +9NWvugeghq7tUv81iJ8ninBefJ4lUfxAehTPQqX+zXcfxgjvMRCi/ig73nLyhmjx +r2AaraPFgrprnxUibP4L7jxdr+iiw5bWN9/B81PodrS7n5TNtnfnpZD6X6rThqOP +xO7Tr5lAo74vNUkF2EHNaI28/RGnJPm2TIxZqy4rNH6L +-----END CERTIFICATE----- +` + + rootCAPath := path.Join(temppath, "foo.example.com") + err := os.WriteFile(rootCAPath, []byte(cert), 0666) + if err != nil { + panic(err) + } + + certPool := x509.NewCertPool() + ok := certPool.AppendCertsFromPEM([]byte(cert)) + assert.True(t, ok) + + testCases := []struct { + name string + scmRootCAPath string + insecure bool + validateCertInTlsConfig bool + }{ + { + name: "Insecure mode configured, SCM Root CA Path not set", + scmRootCAPath: "", + insecure: true, + validateCertInTlsConfig: false, + }, + { + name: "SCM Root CA Path set, Insecure mode set to false", + scmRootCAPath: rootCAPath, + insecure: false, + validateCertInTlsConfig: true, + }, + { + name: "SCM Root CA Path set, Insecure mode set to true", + scmRootCAPath: rootCAPath, + insecure: true, + validateCertInTlsConfig: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + tlsConfig := GetTlsConfig(testCase.scmRootCAPath, testCase.insecure) + assert.Equal(t, testCase.insecure, tlsConfig.InsecureSkipVerify) + if testCase.validateCertInTlsConfig { + assert.NotNil(t, tlsConfig) + assert.True(t, tlsConfig.RootCAs.Equal(certPool)) + } + }) + } +} diff --git a/applicationset/webhook/testdata/azuredevops-pull-request.json b/applicationset/webhook/testdata/azuredevops-pull-request.json new file mode 100644 index 0000000000000..80c5e7cb90822 --- /dev/null +++ b/applicationset/webhook/testdata/azuredevops-pull-request.json @@ -0,0 +1,85 @@ +{ + "id": "2ab4e3d3-b7a6-425e-92b1-5a9982c1269e", + "eventType": "git.pullrequest.created", + "publisherId": "tfs", + "scope": "all", + "message": { + "text": "Jamal Hartnett created a new pull request", + "html": "Jamal Hartnett created a new pull request", + "markdown": "Jamal Hartnett created a new pull request" + }, + "detailedMessage": { + "text": "Jamal Hartnett created a new pull request\r\n\r\n- Merge status: Succeeded\r\n- Merge commit: eef717(https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72)\r\n", + "html": "Jamal Hartnett created a new pull request\r\n
    \r\n
  • Merge status: Succeeded
  • \r\n
  • Merge commit: eef717
  • \r\n
", + "markdown": "Jamal Hartnett created a new pull request\r\n\r\n+ Merge status: Succeeded\r\n+ Merge commit: [eef717](https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72)\r\n" + }, + "resource": { + "repository": { + "id": "4bc14d40-c903-45e2-872e-0462c7748079", + "name": "Fabrikam", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079", + "project": { + "id": "6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "name": "DefaultCollection", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "state": "wellFormed" + }, + "defaultBranch": "refs/heads/master", + "remoteUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_git/Fabrikam" + }, + "pullRequestId": 1, + "status": "active", + "createdBy": { + "id": "54d125f7-69f7-4191-904f-c5b96b6261c8", + "displayName": "Jamal Hartnett", + "uniqueName": "fabrikamfiber4@hotmail.com", + "url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/54d125f7-69f7-4191-904f-c5b96b6261c8", + "imageUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=54d125f7-69f7-4191-904f-c5b96b6261c8" + }, + "creationDate": "2014-06-17T16:55:46.589889Z", + "title": "my first pull request", + "description": " - test2\r\n", + "sourceRefName": "refs/heads/mytopic", + "targetRefName": "refs/heads/master", + "mergeStatus": "succeeded", + "mergeId": "a10bb228-6ba6-4362-abd7-49ea21333dbd", + "lastMergeSourceCommit": { + "commitId": "53d54ac915144006c2c9e90d2c7d3880920db49c", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/53d54ac915144006c2c9e90d2c7d3880920db49c" + }, + "lastMergeTargetCommit": { + "commitId": "a511f535b1ea495ee0c903badb68fbc83772c882", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/a511f535b1ea495ee0c903badb68fbc83772c882" + }, + "lastMergeCommit": { + "commitId": "eef717f69257a6333f221566c1c987dc94cc0d72", + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/commits/eef717f69257a6333f221566c1c987dc94cc0d72" + }, + "reviewers": [ + { + "reviewerUrl": null, + "vote": 0, + "id": "2ea2d095-48f9-4cd6-9966-62f6f574096c", + "displayName": "[Mobile]\\Mobile Team", + "uniqueName": "vstfs:///Classification/TeamProject/f0811a3b-8c8a-4e43-a3bf-9a049b4835bd\\Mobile Team", + "url": "https://vssps.dev.azure.com/fabrikam/_apis/Identities/2ea2d095-48f9-4cd6-9966-62f6f574096c", + "imageUrl": "https://dev.azure.com/fabrikam/DefaultCollection/_api/_common/identityImage?id=2ea2d095-48f9-4cd6-9966-62f6f574096c", + "isContainer": true + } + ], + "url": "https://dev.azure.com/fabrikam/DefaultCollection/_apis/repos/git/repositories/4bc14d40-c903-45e2-872e-0462c7748079/pullRequests/1" + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" + }, + "account": { + "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" + }, + "project": { + "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" + } + }, + "createdDate": "2016-09-19T13:03:27.2879096Z" + } \ No newline at end of file diff --git a/applicationset/webhook/testdata/azuredevops-push.json b/applicationset/webhook/testdata/azuredevops-push.json new file mode 100644 index 0000000000000..41ee074892e39 --- /dev/null +++ b/applicationset/webhook/testdata/azuredevops-push.json @@ -0,0 +1,76 @@ +{ + "id": "03c164c2-8912-4d5e-8009-3707d5f83734", + "eventType": "git.push", + "publisherId": "tfs", + "scope": "all", + "message": { + "text": "Jamal Hartnett pushed updates to branch master of repository Fabrikam-Fiber-Git.", + "html": "Jamal Hartnett pushed updates to branch master of repository Fabrikam-Fiber-Git.", + "markdown": "Jamal Hartnett pushed updates to branch `master` of repository `Fabrikam-Fiber-Git`." + }, + "detailedMessage": { + "text": "Jamal Hartnett pushed 1 commit to branch master of repository Fabrikam-Fiber-Git.\n - Fixed bug in web.config file 33b55f7c", + "html": "Jamal Hartnett pushed 1 commit to branch master of repository Fabrikam-Fiber-Git.\n
    \n
  • Fixed bug in web.config file 33b55f7c\n
", + "markdown": "Jamal Hartnett pushed 1 commit to branch [master](https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git/#version=GBmaster) of repository [Fabrikam-Fiber-Git](https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git/).\n* Fixed bug in web.config file [33b55f7c](https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git/commit/33b55f7cb7e7e245323987634f960cf4a6e6bc74)" + }, + "resource": { + "commits": [ + { + "commitId": "33b55f7cb7e7e245323987634f960cf4a6e6bc74", + "author": { + "name": "Jamal Hartnett", + "email": "fabrikamfiber4@hotmail.com", + "date": "2015-02-25T19:01:00Z" + }, + "committer": { + "name": "Jamal Hartnett", + "email": "fabrikamfiber4@hotmail.com", + "date": "2015-02-25T19:01:00Z" + }, + "comment": "Fixed bug in web.config file", + "url": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git/commit/33b55f7cb7e7e245323987634f960cf4a6e6bc74" + } + ], + "refUpdates": [ + { + "name": "refs/heads/master", + "oldObjectId": "aad331d8d3b131fa9ae03cf5e53965b51942618a", + "newObjectId": "33b55f7cb7e7e245323987634f960cf4a6e6bc74" + } + ], + "repository": { + "id": "278d5cd2-584d-4b63-824a-2ba458937249", + "name": "Fabrikam-Fiber-Git", + "url": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_apis/repos/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249", + "project": { + "id": "6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "name": "DefaultCollection", + "url": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_apis/projects/6ce954b1-ce1f-45d1-b94d-e6bf2464ba2c", + "state": "wellFormed" + }, + "defaultBranch": "refs/heads/master", + "remoteUrl": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git" + }, + "pushedBy": { + "id": "00067FFED5C7AF52@Live.com", + "displayName": "Jamal Hartnett", + "uniqueName": "Windows Live ID\\fabrikamfiber4@hotmail.com" + }, + "pushId": 14, + "date": "2014-05-02T19:17:13.3309587Z", + "url": "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_apis/repos/git/repositories/278d5cd2-584d-4b63-824a-2ba458937249/pushes/14" + }, + "resourceVersion": "1.0", + "resourceContainers": { + "collection": { + "id": "c12d0eb8-e382-443b-9f9c-c52cba5014c2" + }, + "account": { + "id": "f844ec47-a9db-4511-8281-8b63f4eaf94e" + }, + "project": { + "id": "be9b3917-87e6-42a4-a549-2bc06a7a878f" + } + }, + "createdDate": "2016-09-19T13:03:27.0379153Z" + } \ No newline at end of file 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 617f84574a699..d55e63e064f5a 100644 --- a/applicationset/webhook/webhook.go +++ b/applicationset/webhook/webhook.go @@ -2,6 +2,7 @@ package webhook import ( "context" + "errors" "fmt" "html" "net/http" @@ -19,17 +20,24 @@ import ( "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" argosettings "github.com/argoproj/argo-cd/v2/util/settings" + "github.com/go-playground/webhooks/v6/azuredevops" + "github.com/go-playground/webhooks/v6/github" + "github.com/go-playground/webhooks/v6/gitlab" log "github.com/sirupsen/logrus" - "gopkg.in/go-playground/webhooks.v5/github" - "gopkg.in/go-playground/webhooks.v5/gitlab" +) + +var ( + errBasicAuthVerificationFailed = errors.New("basic auth verification failed") ) type WebhookHandler struct { - namespace string - github *github.Webhook - gitlab *gitlab.Webhook - client client.Client - generators map[string]generators.Generator + namespace string + github *github.Webhook + gitlab *gitlab.Webhook + azuredevops *azuredevops.Webhook + azuredevopsAuthHandler func(r *http.Request) error + client client.Client + generators map[string]generators.Generator } type gitGeneratorInfo struct { @@ -39,8 +47,14 @@ type gitGeneratorInfo struct { } type prGeneratorInfo struct { - Github *prGeneratorGithubInfo - Gitlab *prGeneratorGitlabInfo + Azuredevops *prGeneratorAzuredevopsInfo + Github *prGeneratorGithubInfo + Gitlab *prGeneratorGitlabInfo +} + +type prGeneratorAzuredevopsInfo struct { + Repo string + Project string } type prGeneratorGithubInfo struct { @@ -68,13 +82,28 @@ func NewWebhookHandler(namespace string, argocdSettingsMgr *argosettings.Setting if err != nil { return nil, fmt.Errorf("Unable to init GitLab webhook: %v", err) } + azuredevopsHandler, err := azuredevops.New() + if err != nil { + return nil, fmt.Errorf("Unable to init Azure DevOps webhook: %v", err) + } + azuredevopsAuthHandler := func(r *http.Request) error { + if argocdSettings.WebhookAzureDevOpsUsername != "" && argocdSettings.WebhookAzureDevOpsPassword != "" { + username, password, ok := r.BasicAuth() + if !ok || username != argocdSettings.WebhookAzureDevOpsUsername || password != argocdSettings.WebhookAzureDevOpsPassword { + return errBasicAuthVerificationFailed + } + } + return nil + } return &WebhookHandler{ - namespace: namespace, - github: githubHandler, - gitlab: gitlabHandler, - client: client, - generators: generators, + namespace: namespace, + github: githubHandler, + gitlab: gitlabHandler, + azuredevops: azuredevopsHandler, + azuredevopsAuthHandler: azuredevopsAuthHandler, + client: client, + generators: generators, }, nil } @@ -98,6 +127,7 @@ func (h *WebhookHandler) HandleEvent(payload interface{}) { // check if the ApplicationSet uses any generator that is relevant to the payload shouldRefresh = shouldRefreshGitGenerator(gen.Git, gitGenInfo) || shouldRefreshPRGenerator(gen.PullRequest, prGenInfo) || + shouldRefreshPluginGenerator(gen.Plugin) || h.shouldRefreshMatrixGenerator(gen.Matrix, &appSet, gitGenInfo, prGenInfo) || h.shouldRefreshMergeGenerator(gen.Merge, &appSet, gitGenInfo, prGenInfo) if shouldRefresh { @@ -124,6 +154,14 @@ func (h *WebhookHandler) Handler(w http.ResponseWriter, r *http.Request) { payload, err = h.github.Parse(r, github.PushEvent, github.PullRequestEvent, github.PingEvent) case r.Header.Get("X-Gitlab-Event") != "": payload, err = h.gitlab.Parse(r, gitlab.PushEvents, gitlab.TagEvents, gitlab.MergeRequestEvents) + case r.Header.Get("X-Vss-Activityid") != "": + if err = h.azuredevopsAuthHandler(r); err != nil { + if errors.Is(err, errBasicAuthVerificationFailed) { + log.WithField(common.SecurityField, common.SecurityHigh).Infof("Azure DevOps webhook basic auth verification failed") + } + } else { + payload, err = h.azuredevops.Parse(r, azuredevops.GitPushEventType, azuredevops.GitPullRequestCreatedEventType, azuredevops.GitPullRequestUpdatedEventType, azuredevops.GitPullRequestMergedEventType) + } default: log.Debug("Ignoring unknown webhook event") http.Error(w, "Unknown webhook event", http.StatusBadRequest) @@ -133,7 +171,7 @@ func (h *WebhookHandler) Handler(w http.ResponseWriter, r *http.Request) { if err != nil { log.Infof("Webhook processing failed: %s", err) status := http.StatusBadRequest - if r.Method != "POST" { + if r.Method != http.MethodPost { status = http.StatusMethodNotAllowed } http.Error(w, fmt.Sprintf("Webhook processing failed: %s", html.EscapeString(err.Error())), status) @@ -163,6 +201,12 @@ func getGitGeneratorInfo(payload interface{}) *gitGeneratorInfo { webURL = payload.Project.WebURL revision = parseRevision(payload.Ref) touchedHead = payload.Project.DefaultBranch == revision + case azuredevops.GitPushEvent: + // See: https://learn.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops#git.push + webURL = payload.Resource.Repository.RemoteURL + revision = parseRevision(payload.Resource.RefUpdates[0].Name) + touchedHead = payload.Resource.RefUpdates[0].Name == payload.Resource.Repository.DefaultBranch + // unfortunately, Azure DevOps doesn't provide a list of changed files default: return nil } @@ -228,6 +272,18 @@ func getPRGeneratorInfo(payload interface{}) *prGeneratorInfo { Project: strconv.FormatInt(payload.ObjectAttributes.TargetProjectID, 10), APIHostname: urlObj.Hostname(), } + case azuredevops.GitPullRequestEvent: + if !isAllowedAzureDevOpsPullRequestAction(string(payload.EventType)) { + return nil + } + + repo := payload.Resource.Repository.Name + project := payload.Resource.Repository.Project.Name + + info.Azuredevops = &prGeneratorAzuredevopsInfo{ + Repo: repo, + Project: project, + } default: return nil } @@ -255,6 +311,13 @@ var gitlabAllowedPullRequestActions = []string{ "merge", } +// azuredevopsAllowedPullRequestActions is a list of Azure DevOps actions that allow refresh +var azuredevopsAllowedPullRequestActions = []string{ + "git.pullrequest.created", + "git.pullrequest.merged", + "git.pullrequest.updated", +} + func isAllowedGithubPullRequestAction(action string) bool { for _, allow := range githubAllowedPullRequestActions { if allow == action { @@ -273,6 +336,15 @@ func isAllowedGitlabPullRequestAction(action string) bool { return false } +func isAllowedAzureDevOpsPullRequestAction(action string) bool { + for _, allow := range azuredevopsAllowedPullRequestActions { + if allow == action { + return true + } + } + return false +} + func shouldRefreshGitGenerator(gen *v1alpha1.GitGenerator, info *gitGeneratorInfo) bool { if gen == nil || info == nil { return false @@ -287,6 +359,10 @@ func shouldRefreshGitGenerator(gen *v1alpha1.GitGenerator, info *gitGeneratorInf return true } +func shouldRefreshPluginGenerator(gen *v1alpha1.PluginGenerator) bool { + return gen != nil +} + func genRevisionHasChanged(gen *v1alpha1.GitGenerator, revision string, touchedHead bool) bool { targetRev := parseRevision(gen.Revision) if targetRev == "HEAD" || targetRev == "" { // revision is head @@ -336,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 @@ -354,6 +432,16 @@ func shouldRefreshPRGenerator(gen *v1alpha1.PullRequestGenerator, info *prGenera return true } + if gen.AzureDevOps != nil && info.Azuredevops != nil { + if gen.AzureDevOps.Project != info.Azuredevops.Project { + return false + } + if gen.AzureDevOps.Repo != info.Azuredevops.Repo { + return false + } + return true + } + return false } @@ -417,6 +505,7 @@ func (h *WebhookHandler) shouldRefreshMatrixGenerator(gen *v1alpha1.MatrixGenera SCMProvider: g0.SCMProvider, ClusterDecisionResource: g0.ClusterDecisionResource, PullRequest: g0.PullRequest, + Plugin: g0.Plugin, Matrix: matrixGenerator0, Merge: mergeGenerator0, } @@ -471,6 +560,7 @@ func (h *WebhookHandler) shouldRefreshMatrixGenerator(gen *v1alpha1.MatrixGenera SCMProvider: g1.SCMProvider, ClusterDecisionResource: g1.ClusterDecisionResource, PullRequest: g1.PullRequest, + Plugin: g1.Plugin, Matrix: matrixGenerator1, Merge: mergeGenerator1, } @@ -478,7 +568,7 @@ func (h *WebhookHandler) shouldRefreshMatrixGenerator(gen *v1alpha1.MatrixGenera // Interpolate second child generator with params from first child generator, if there are any params if len(params) != 0 { for _, p := range params { - tempInterpolatedGenerator, err := generators.InterpolateGenerator(requestedGenerator1, p, appSet.Spec.GoTemplate) + tempInterpolatedGenerator, err := generators.InterpolateGenerator(requestedGenerator1, p, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions) interpolatedGenerator := &tempInterpolatedGenerator if err != nil { log.Error(err) @@ -488,6 +578,7 @@ func (h *WebhookHandler) shouldRefreshMatrixGenerator(gen *v1alpha1.MatrixGenera // Check all interpolated child generators if shouldRefreshGitGenerator(interpolatedGenerator.Git, gitGenInfo) || shouldRefreshPRGenerator(interpolatedGenerator.PullRequest, prGenInfo) || + shouldRefreshPluginGenerator(interpolatedGenerator.Plugin) || h.shouldRefreshMatrixGenerator(interpolatedGenerator.Matrix, appSet, gitGenInfo, prGenInfo) || h.shouldRefreshMergeGenerator(requestedGenerator1.Merge, appSet, gitGenInfo, prGenInfo) { return true @@ -498,6 +589,7 @@ func (h *WebhookHandler) shouldRefreshMatrixGenerator(gen *v1alpha1.MatrixGenera // First child generator didn't return any params, just check the second child generator return shouldRefreshGitGenerator(requestedGenerator1.Git, gitGenInfo) || shouldRefreshPRGenerator(requestedGenerator1.PullRequest, prGenInfo) || + shouldRefreshPluginGenerator(requestedGenerator1.Plugin) || h.shouldRefreshMatrixGenerator(requestedGenerator1.Matrix, appSet, gitGenInfo, prGenInfo) || h.shouldRefreshMergeGenerator(requestedGenerator1.Merge, appSet, gitGenInfo, prGenInfo) } @@ -553,7 +645,7 @@ func refreshApplicationSet(c client.Client, appSet *v1alpha1.ApplicationSet) err return retry.RetryOnConflict(retry.DefaultBackoff, func() error { err := c.Get(context.Background(), types.NamespacedName{Name: appSet.Name, Namespace: appSet.Namespace}, appSet) if err != nil { - return err + return fmt.Errorf("error getting ApplicationSet: %w", err) } if appSet.Annotations == nil { appSet.Annotations = map[string]string{} diff --git a/applicationset/webhook/webhook_test.go b/applicationset/webhook/webhook_test.go index c1e0a7eba3e18..d22b1a07ca6f2 100644 --- a/applicationset/webhook/webhook_test.go +++ b/applicationset/webhook/webhook_test.go @@ -15,34 +15,33 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" kubefake "k8s.io/client-go/kubernetes/fake" "sigs.k8s.io/controller-runtime/pkg/client/fake" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "github.com/argoproj/argo-cd/v2/applicationset/generators" "github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider" "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" argosettings "github.com/argoproj/argo-cd/v2/util/settings" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" ) type generatorMock struct { mock.Mock } -func (g *generatorMock) GetTemplate(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) *argoprojiov1alpha1.ApplicationSetTemplate { - return &argoprojiov1alpha1.ApplicationSetTemplate{} +func (g *generatorMock) GetTemplate(appSetGenerator *v1alpha1.ApplicationSetGenerator) *v1alpha1.ApplicationSetTemplate { + return &v1alpha1.ApplicationSetTemplate{} } -func (g *generatorMock) GenerateParams(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, _ *argoprojiov1alpha1.ApplicationSet) ([]map[string]interface{}, error) { +func (g *generatorMock) GenerateParams(appSetGenerator *v1alpha1.ApplicationSetGenerator, _ *v1alpha1.ApplicationSet) ([]map[string]interface{}, error) { return []map[string]interface{}{}, nil } -func (g *generatorMock) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration { +func (g *generatorMock) GetRequeueAfter(appSetGenerator *v1alpha1.ApplicationSetGenerator) time.Duration { d, _ := time.ParseDuration("10s") return d } @@ -62,7 +61,7 @@ func TestWebhookHandler(t *testing.T) { headerKey: "X-GitHub-Event", headerValue: "push", payloadFile: "github-commit-event.json", - effectedAppSets: []string{"git-github", "matrix-git-github", "merge-git-github", "matrix-scm-git-github", "matrix-nested-git-github", "merge-nested-git-github"}, + effectedAppSets: []string{"git-github", "matrix-git-github", "merge-git-github", "matrix-scm-git-github", "matrix-nested-git-github", "merge-nested-git-github", "plugin", "matrix-pull-request-github-plugin"}, expectedStatusCode: http.StatusOK, expectedRefresh: true, }, @@ -71,7 +70,7 @@ func TestWebhookHandler(t *testing.T) { headerKey: "X-GitHub-Event", headerValue: "push", payloadFile: "github-commit-branch-event.json", - effectedAppSets: []string{"git-github"}, + effectedAppSets: []string{"git-github", "plugin", "matrix-pull-request-github-plugin"}, expectedStatusCode: http.StatusOK, expectedRefresh: true, }, @@ -80,7 +79,7 @@ func TestWebhookHandler(t *testing.T) { headerKey: "X-GitHub-Event", headerValue: "ping", payloadFile: "github-ping-event.json", - effectedAppSets: []string{"git-github"}, + effectedAppSets: []string{"git-github", "plugin"}, expectedStatusCode: http.StatusOK, expectedRefresh: false, }, @@ -89,7 +88,7 @@ func TestWebhookHandler(t *testing.T) { headerKey: "X-Gitlab-Event", headerValue: "Push Hook", payloadFile: "gitlab-event.json", - effectedAppSets: []string{"git-gitlab"}, + effectedAppSets: []string{"git-gitlab", "plugin", "matrix-pull-request-github-plugin"}, expectedStatusCode: http.StatusOK, expectedRefresh: true, }, @@ -98,7 +97,7 @@ func TestWebhookHandler(t *testing.T) { headerKey: "X-Random-Event", headerValue: "Push Hook", payloadFile: "gitlab-event.json", - effectedAppSets: []string{"git-gitlab"}, + effectedAppSets: []string{"git-gitlab", "plugin"}, expectedStatusCode: http.StatusBadRequest, expectedRefresh: false, }, @@ -107,34 +106,43 @@ func TestWebhookHandler(t *testing.T) { headerKey: "X-Random-Event", headerValue: "Push Hook", payloadFile: "invalid-event.json", - effectedAppSets: []string{"git-gitlab"}, + effectedAppSets: []string{"git-gitlab", "plugin"}, expectedStatusCode: http.StatusBadRequest, 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", - effectedAppSets: []string{"pull-request-github", "matrix-pull-request-github", "matrix-scm-pull-request-github", "merge-pull-request-github"}, + 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 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", - effectedAppSets: []string{"pull-request-github", "matrix-pull-request-github", "matrix-scm-pull-request-github", "merge-pull-request-github"}, + 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: 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", headerValue: "Merge Request Hook", payloadFile: "gitlab-merge-request-open-event.json", - effectedAppSets: []string{"pull-request-gitlab"}, + effectedAppSets: []string{"pull-request-gitlab", "plugin", "matrix-pull-request-github-plugin"}, expectedStatusCode: http.StatusOK, expectedRefresh: true, }, @@ -143,10 +151,28 @@ func TestWebhookHandler(t *testing.T) { headerKey: "X-Gitlab-Event", headerValue: "Merge Request Hook", payloadFile: "gitlab-merge-request-approval-event.json", - effectedAppSets: []string{"pull-request-gitlab"}, + effectedAppSets: []string{"pull-request-gitlab", "plugin"}, expectedStatusCode: http.StatusOK, expectedRefresh: false, }, + { + desc: "WebHook from a Azure DevOps repository via Commit", + headerKey: "X-Vss-Activityid", + headerValue: "Push Hook", + payloadFile: "azuredevops-push.json", + effectedAppSets: []string{"git-azure-devops", "plugin", "matrix-pull-request-github-plugin"}, + expectedStatusCode: http.StatusOK, + expectedRefresh: true, + }, + { + desc: "WebHook from a Azure DevOps repository via pull request event", + headerKey: "X-Vss-Activityid", + headerValue: "Pull Request Hook", + payloadFile: "azuredevops-pull-request.json", + effectedAppSets: []string{"pull-request-azure-devops", "plugin", "matrix-pull-request-github-plugin"}, + expectedStatusCode: http.StatusOK, + expectedRefresh: true, + }, } namespace := "test" @@ -162,13 +188,17 @@ func TestWebhookHandler(t *testing.T) { fc := fake.NewClientBuilder().WithScheme(scheme).WithObjects( fakeAppWithGitGenerator("git-github", namespace, "https://github.com/org/repo"), fakeAppWithGitGenerator("git-gitlab", namespace, "https://gitlab/group/name"), - fakeAppWithGithubPullRequestGenerator("pull-request-github", namespace, "Codertocat", "Hello-World"), + 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"), fakeAppWithGitlabPullRequestGenerator("pull-request-gitlab", namespace, "100500"), + fakeAppWithAzureDevOpsPullRequestGenerator("pull-request-azure-devops", namespace, "DefaultCollection", "Fabrikam"), + fakeAppWithPluginGenerator("plugin", namespace), fakeAppWithMatrixAndGitGenerator("matrix-git-github", namespace, "https://github.com/org/repo"), fakeAppWithMatrixAndPullRequestGenerator("matrix-pull-request-github", namespace, "Codertocat", "Hello-World"), 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"), 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"), @@ -177,7 +207,7 @@ func TestWebhookHandler(t *testing.T) { h, err := NewWebhookHandler(namespace, set, fc, mockGenerators()) assert.Nil(t, err) - req := httptest.NewRequest("POST", "/api/webhook", nil) + req := httptest.NewRequest(http.MethodPost, "/api/webhook", nil) req.Header.Set(test.headerKey, test.headerValue) eventJSON, err := os.ReadFile(filepath.Join("testdata", test.payloadFile)) assert.NoError(t, err) @@ -216,6 +246,7 @@ func mockGenerators() map[string]generators.Generator { // generatorMockList := generatorMock{} generatorMockGit := &generatorMock{} generatorMockPR := &generatorMock{} + generatorMockPlugin := &generatorMock{} mockSCMProvider := &scm_provider.MockProvider{ Repos: []*scm_provider.Repository{ { @@ -241,6 +272,7 @@ func mockGenerators() map[string]generators.Generator { "Git": generatorMockGit, "SCMProvider": generatorMockSCM, "PullRequest": generatorMockPR, + "Plugin": generatorMockPlugin, } nestedGenerators := map[string]generators.Generator{ @@ -248,6 +280,7 @@ func mockGenerators() map[string]generators.Generator { "Git": terminalMockGenerators["Git"], "SCMProvider": terminalMockGenerators["SCMProvider"], "PullRequest": terminalMockGenerators["PullRequest"], + "Plugin": terminalMockGenerators["Plugin"], "Matrix": generators.NewMatrixGenerator(terminalMockGenerators), "Merge": generators.NewMergeGenerator(terminalMockGenerators), } @@ -257,20 +290,21 @@ func mockGenerators() map[string]generators.Generator { "Git": terminalMockGenerators["Git"], "SCMProvider": terminalMockGenerators["SCMProvider"], "PullRequest": terminalMockGenerators["PullRequest"], + "Plugin": terminalMockGenerators["Plugin"], "Matrix": generators.NewMatrixGenerator(nestedGenerators), "Merge": generators.NewMergeGenerator(nestedGenerators), } } func TestGenRevisionHasChanged(t *testing.T) { - assert.True(t, genRevisionHasChanged(&argoprojiov1alpha1.GitGenerator{}, "master", true)) - assert.False(t, genRevisionHasChanged(&argoprojiov1alpha1.GitGenerator{}, "master", false)) + assert.True(t, genRevisionHasChanged(&v1alpha1.GitGenerator{}, "master", true)) + assert.False(t, genRevisionHasChanged(&v1alpha1.GitGenerator{}, "master", false)) - assert.True(t, genRevisionHasChanged(&argoprojiov1alpha1.GitGenerator{Revision: "dev"}, "dev", true)) - assert.False(t, genRevisionHasChanged(&argoprojiov1alpha1.GitGenerator{Revision: "dev"}, "master", false)) + assert.True(t, genRevisionHasChanged(&v1alpha1.GitGenerator{Revision: "dev"}, "dev", true)) + assert.False(t, genRevisionHasChanged(&v1alpha1.GitGenerator{Revision: "dev"}, "master", false)) - assert.True(t, genRevisionHasChanged(&argoprojiov1alpha1.GitGenerator{Revision: "refs/heads/dev"}, "dev", true)) - assert.False(t, genRevisionHasChanged(&argoprojiov1alpha1.GitGenerator{Revision: "refs/heads/dev"}, "master", false)) + assert.True(t, genRevisionHasChanged(&v1alpha1.GitGenerator{Revision: "refs/heads/dev"}, "dev", true)) + assert.False(t, genRevisionHasChanged(&v1alpha1.GitGenerator{Revision: "refs/heads/dev"}, "master", false)) } func fakeAppWithGitGenerator(name, namespace, repo string) *v1alpha1.ApplicationSet { @@ -292,17 +326,17 @@ func fakeAppWithGitGenerator(name, namespace, repo string) *v1alpha1.Application } } -func fakeAppWithGitlabPullRequestGenerator(name, namespace, projectId string) *argoprojiov1alpha1.ApplicationSet { - return &argoprojiov1alpha1.ApplicationSet{ +func fakeAppWithGitlabPullRequestGenerator(name, namespace, projectId string) *v1alpha1.ApplicationSet { + return &v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, }, - Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Generators: []argoprojiov1alpha1.ApplicationSetGenerator{ + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ { - PullRequest: &argoprojiov1alpha1.PullRequestGenerator{ - GitLab: &argoprojiov1alpha1.PullRequestGeneratorGitLab{ + PullRequest: &v1alpha1.PullRequestGenerator{ + GitLab: &v1alpha1.PullRequestGeneratorGitLab{ Project: projectId, }, }, @@ -312,8 +346,8 @@ func fakeAppWithGitlabPullRequestGenerator(name, namespace, projectId string) *a } } -func fakeAppWithGithubPullRequestGenerator(name, namespace, owner, repo string) *argoprojiov1alpha1.ApplicationSet { - return &argoprojiov1alpha1.ApplicationSet{ +func fakeAppWithGithubPullRequestGenerator(name, namespace, owner, repo string) *v1alpha1.ApplicationSet { + return &v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, @@ -333,6 +367,27 @@ func fakeAppWithGithubPullRequestGenerator(name, namespace, owner, repo string) } } +func fakeAppWithAzureDevOpsPullRequestGenerator(name, namespace, project, repo string) *v1alpha1.ApplicationSet { + return &v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ + { + PullRequest: &v1alpha1.PullRequestGenerator{ + AzureDevOps: &v1alpha1.PullRequestGeneratorAzureDevOps{ + Project: project, + Repo: repo, + }, + }, + }, + }, + }, + } +} + func fakeAppWithMatrixAndGitGenerator(name, namespace, repo string) *v1alpha1.ApplicationSet { return &v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ @@ -345,10 +400,10 @@ func fakeAppWithMatrixAndGitGenerator(name, namespace, repo string) *v1alpha1.Ap Matrix: &v1alpha1.MatrixGenerator{ Generators: []v1alpha1.ApplicationSetNestedGenerator{ { - List: &argoprojiov1alpha1.ListGenerator{}, + List: &v1alpha1.ListGenerator{}, }, { - Git: &argoprojiov1alpha1.GitGenerator{ + Git: &v1alpha1.GitGenerator{ RepoURL: repo, }, }, @@ -372,11 +427,11 @@ func fakeAppWithMatrixAndPullRequestGenerator(name, namespace, owner, repo strin Matrix: &v1alpha1.MatrixGenerator{ Generators: []v1alpha1.ApplicationSetNestedGenerator{ { - List: &argoprojiov1alpha1.ListGenerator{}, + List: &v1alpha1.ListGenerator{}, }, { - PullRequest: &argoprojiov1alpha1.PullRequestGenerator{ - Github: &argoprojiov1alpha1.PullRequestGeneratorGithub{ + PullRequest: &v1alpha1.PullRequestGenerator{ + Github: &v1alpha1.PullRequestGeneratorGithub{ Owner: owner, Repo: repo, }, @@ -390,27 +445,27 @@ func fakeAppWithMatrixAndPullRequestGenerator(name, namespace, owner, repo strin } } -func fakeAppWithMatrixAndScmWithGitGenerator(name, namespace, owner string) *argoprojiov1alpha1.ApplicationSet { - return &argoprojiov1alpha1.ApplicationSet{ +func fakeAppWithMatrixAndScmWithGitGenerator(name, namespace, owner string) *v1alpha1.ApplicationSet { + return &v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, }, - Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Generators: []argoprojiov1alpha1.ApplicationSetGenerator{ + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ { - Matrix: &argoprojiov1alpha1.MatrixGenerator{ - Generators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{ + Matrix: &v1alpha1.MatrixGenerator{ + Generators: []v1alpha1.ApplicationSetNestedGenerator{ { - SCMProvider: &argoprojiov1alpha1.SCMProviderGenerator{ + SCMProvider: &v1alpha1.SCMProviderGenerator{ CloneProtocol: "ssh", - Github: &argoprojiov1alpha1.SCMProviderGeneratorGithub{ + Github: &v1alpha1.SCMProviderGeneratorGithub{ Organization: owner, }, }, }, { - Git: &argoprojiov1alpha1.GitGenerator{ + Git: &v1alpha1.GitGenerator{ RepoURL: "{{ url }}", }, }, @@ -422,28 +477,28 @@ func fakeAppWithMatrixAndScmWithGitGenerator(name, namespace, owner string) *arg } } -func fakeAppWithMatrixAndScmWithPullRequestGenerator(name, namespace, owner string) *argoprojiov1alpha1.ApplicationSet { - return &argoprojiov1alpha1.ApplicationSet{ +func fakeAppWithMatrixAndScmWithPullRequestGenerator(name, namespace, owner string) *v1alpha1.ApplicationSet { + return &v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, }, - Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Generators: []argoprojiov1alpha1.ApplicationSetGenerator{ + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ { - Matrix: &argoprojiov1alpha1.MatrixGenerator{ - Generators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{ + Matrix: &v1alpha1.MatrixGenerator{ + Generators: []v1alpha1.ApplicationSetNestedGenerator{ { - SCMProvider: &argoprojiov1alpha1.SCMProviderGenerator{ + SCMProvider: &v1alpha1.SCMProviderGenerator{ CloneProtocol: "https", - Github: &argoprojiov1alpha1.SCMProviderGeneratorGithub{ + Github: &v1alpha1.SCMProviderGeneratorGithub{ Organization: owner, }, }, }, { - PullRequest: &argoprojiov1alpha1.PullRequestGenerator{ - Github: &argoprojiov1alpha1.PullRequestGeneratorGithub{ + PullRequest: &v1alpha1.PullRequestGenerator{ + Github: &v1alpha1.PullRequestGeneratorGithub{ Owner: "{{ organization }}", Repo: "{{ repository }}", }, @@ -457,19 +512,19 @@ func fakeAppWithMatrixAndScmWithPullRequestGenerator(name, namespace, owner stri } } -func fakeAppWithMatrixAndNestedGitGenerator(name, namespace, repo string) *argoprojiov1alpha1.ApplicationSet { - return &argoprojiov1alpha1.ApplicationSet{ +func fakeAppWithMatrixAndNestedGitGenerator(name, namespace, repo string) *v1alpha1.ApplicationSet { + return &v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, }, - Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Generators: []argoprojiov1alpha1.ApplicationSetGenerator{ + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ { - Matrix: &argoprojiov1alpha1.MatrixGenerator{ - Generators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{ + Matrix: &v1alpha1.MatrixGenerator{ + Generators: []v1alpha1.ApplicationSetNestedGenerator{ { - List: &argoprojiov1alpha1.ListGenerator{}, + List: &v1alpha1.ListGenerator{}, }, { Matrix: &apiextensionsv1.JSON{ @@ -501,8 +556,8 @@ func fakeAppWithMatrixAndNestedGitGenerator(name, namespace, repo string) *argop } } -func fakeAppWithMergeAndGitGenerator(name, namespace, repo string) *argoprojiov1alpha1.ApplicationSet { - return &argoprojiov1alpha1.ApplicationSet{ +func fakeAppWithMergeAndGitGenerator(name, namespace, repo string) *v1alpha1.ApplicationSet { + return &v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, @@ -552,22 +607,22 @@ func fakeAppWithMergeAndPullRequestGenerator(name, namespace, owner, repo string } } -func fakeAppWithMergeAndNestedGitGenerator(name, namespace, repo string) *argoprojiov1alpha1.ApplicationSet { - return &argoprojiov1alpha1.ApplicationSet{ +func fakeAppWithMergeAndNestedGitGenerator(name, namespace, repo string) *v1alpha1.ApplicationSet { + return &v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: namespace, }, - Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Generators: []argoprojiov1alpha1.ApplicationSetGenerator{ + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ { - Merge: &argoprojiov1alpha1.MergeGenerator{ + Merge: &v1alpha1.MergeGenerator{ MergeKeys: []string{ "server", }, - Generators: []argoprojiov1alpha1.ApplicationSetNestedGenerator{ + Generators: []v1alpha1.ApplicationSetNestedGenerator{ { - List: &argoprojiov1alpha1.ListGenerator{}, + List: &v1alpha1.ListGenerator{}, }, { Merge: &apiextensionsv1.JSON{ @@ -594,12 +649,66 @@ func fakeAppWithMergeAndNestedGitGenerator(name, namespace, repo string) *argopr } } +func fakeAppWithPluginGenerator(name, namespace string) *v1alpha1.ApplicationSet { + return &v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ + { + Plugin: &v1alpha1.PluginGenerator{ + ConfigMapRef: v1alpha1.PluginConfigMapRef{ + Name: "test", + }, + }, + }, + }, + }, + } +} + +func fakeAppWithMatrixAndPullRequestGeneratorWithPluginGenerator(name, namespace, owner, repo, configmapName string) *v1alpha1.ApplicationSet { + return &v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ + { + Matrix: &v1alpha1.MatrixGenerator{ + Generators: []v1alpha1.ApplicationSetNestedGenerator{ + { + PullRequest: &v1alpha1.PullRequestGenerator{ + Github: &v1alpha1.PullRequestGeneratorGithub{ + Owner: owner, + Repo: repo, + }, + }, + }, + { + Plugin: &v1alpha1.PluginGenerator{ + ConfigMapRef: v1alpha1.PluginConfigMapRef{ + Name: configmapName, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + func newFakeClient(ns string) *kubefake.Clientset { s := runtime.NewScheme() s.AddKnownTypes(v1alpha1.SchemeGroupVersion, &v1alpha1.ApplicationSet{}) return kubefake.NewSimpleClientset(&corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "argocd-cm", Namespace: ns, Labels: map[string]string{ "app.kubernetes.io/part-of": "argocd", - }}}, &v1.Secret{ + }}}, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: common.ArgoCDSecretName, Namespace: ns, diff --git a/assets/badge.svg b/assets/badge.svg index cc216ccdd1508..f1dab6b6cb711 100644 --- a/assets/badge.svg +++ b/assets/badge.svg @@ -5,6 +5,7 @@ + @@ -14,6 +15,7 @@ + diff --git a/assets/embed.go b/assets/embed.go index 8095b0f282df3..ac148cafd3de6 100644 --- a/assets/embed.go +++ b/assets/embed.go @@ -3,5 +3,6 @@ package assets import "embed" // Embedded contains embedded assets +// //go:embed * var Embedded embed.FS diff --git a/assets/swagger.json b/assets/swagger.json index bd38517972ded..31d771c52f398 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" }, @@ -271,6 +271,16 @@ "description": "the application's namespace.", "name": "appNamespace", "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "the project names to restrict returned list applications (legacy name for backwards-compatibility).", + "name": "project", + "in": "query" } ], "responses": { @@ -391,6 +401,11 @@ "type": "boolean", "name": "validate", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -452,6 +467,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -513,6 +533,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -548,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" }, @@ -585,6 +610,16 @@ "description": "the application's namespace.", "name": "appNamespace", "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "the project names to restrict returned list applications (legacy name for backwards-compatibility).", + "name": "project", + "in": "query" } ], "responses": { @@ -629,6 +664,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -717,6 +757,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -753,6 +798,11 @@ "type": "string", "name": "namespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -865,6 +915,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -915,6 +970,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -951,6 +1011,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -1064,6 +1129,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -1134,6 +1204,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -1206,6 +1281,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -1275,6 +1355,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -1336,6 +1421,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -1403,6 +1493,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -1464,6 +1559,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -1482,6 +1582,56 @@ } } }, + "/api/v1/applications/{name}/revisions/{revision}/chartdetails": { + "get": { + "tags": [ + "ApplicationService" + ], + "summary": "Get the chart metadata (description, maintainers, home) for a specific revision of the application", + "operationId": "ApplicationService_RevisionChartDetails", + "parameters": [ + { + "type": "string", + "description": "the application's name", + "name": "name", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "the revision of the app", + "name": "revision", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "the application's namespace.", + "name": "appNamespace", + "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1alpha1ChartDetails" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/runtimeError" + } + } + } + } + }, "/api/v1/applications/{name}/revisions/{revision}/metadata": { "get": { "tags": [ @@ -1509,6 +1659,11 @@ "description": "the application's namespace.", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -1597,6 +1752,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -1672,6 +1832,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -1713,6 +1878,12 @@ "description": "the selector to restrict returned list to applications only with matched labels.", "name": "selector", "in": "query" + }, + { + "type": "string", + "description": "The application set namespace. Default empty is argocd control plane namespace.", + "name": "appsetNamespace", + "in": "query" } ], "responses": { @@ -1781,6 +1952,12 @@ "name": "name", "in": "path", "required": true + }, + { + "type": "string", + "description": "The application set namespace. Default empty is argocd control plane namespace.", + "name": "appsetNamespace", + "in": "query" } ], "responses": { @@ -1810,6 +1987,12 @@ "name": "name", "in": "path", "required": true + }, + { + "type": "string", + "description": "The application set namespace. Default empty is argocd control plane namespace.", + "name": "appsetNamespace", + "in": "query" } ], "responses": { @@ -3430,6 +3613,12 @@ "description": "Google Cloud Platform service account key.", "name": "gcpServiceAccountKey", "in": "query" + }, + { + "type": "boolean", + "description": "Whether to force HTTP basic auth.", + "name": "forceHttpBasicAuth", + "in": "query" } ], "responses": { @@ -3588,6 +3777,29 @@ } } }, + "/api/v1/settings/plugins": { + "get": { + "tags": [ + "SettingsService" + ], + "summary": "Get returns Argo CD plugins", + "operationId": "SettingsService_GetPlugins", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/clusterSettingsPluginsResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/runtimeError" + } + } + } + } + }, "/api/v1/stream/applications": { "get": { "tags": [ @@ -3604,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" }, @@ -3641,6 +3853,16 @@ "description": "the application's namespace.", "name": "appNamespace", "in": "query" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi", + "description": "the project names to restrict returned list applications (legacy name for backwards-compatibility).", + "name": "project", + "in": "query" } ], "responses": { @@ -3711,6 +3933,11 @@ "type": "string", "name": "appNamespace", "in": "query" + }, + { + "type": "string", + "name": "project", + "in": "query" } ], "responses": { @@ -3809,7 +4036,7 @@ "type": "object", "properties": { "expiresIn": { - "type": "string", + "type": "integer", "format": "int64", "title": "expiresIn represents a duration in seconds" }, @@ -3836,14 +4063,14 @@ "type": "object", "properties": { "expiresAt": { - "type": "string", + "type": "integer", "format": "int64" }, "id": { "type": "string" }, "issuedAt": { - "type": "string", + "type": "integer", "format": "int64" } } @@ -3876,6 +4103,9 @@ }, "name": { "type": "string" + }, + "project": { + "type": "string" } } }, @@ -3905,6 +4135,9 @@ }, "patchType": { "type": "string" + }, + "project": { + "type": "string" } } }, @@ -3929,12 +4162,15 @@ "type": "boolean" }, "id": { - "type": "string", + "type": "integer", "format": "int64" }, "name": { "type": "string" }, + "project": { + "type": "string" + }, "prune": { "type": "boolean" } @@ -3965,6 +4201,9 @@ "name": { "type": "string" }, + "project": { + "type": "string" + }, "prune": { "type": "boolean" }, @@ -4223,6 +4462,9 @@ "clientID": { "type": "string" }, + "enablePKCEAuthentication": { + "type": "boolean" + }, "idTokenClaims": { "type": "object", "additionalProperties": { @@ -4263,6 +4505,7 @@ "type": "boolean" }, "configManagementPlugins": { + "description": "Deprecated: use sidecar plugins instead.", "type": "array", "items": { "$ref": "#/definitions/v1alpha1ConfigManagementPlugin" @@ -4342,6 +4585,17 @@ } } }, + "clusterSettingsPluginsResponse": { + "type": "object", + "properties": { + "plugins": { + "type": "array", + "items": { + "$ref": "#/definitions/clusterPlugin" + } + } + } + }, "gpgkeyGnuPGPublicKeyCreateResponse": { "type": "object", "title": "Response to a public key creation request", @@ -4375,7 +4629,7 @@ "type": "string" }, "type": { - "type": "string", + "type": "integer", "format": "int64" } } @@ -4514,7 +4768,7 @@ "type": "string" }, "expiresIn": { - "type": "string", + "type": "integer", "format": "int64", "title": "expiresIn represents a duration in seconds" }, @@ -4837,6 +5091,17 @@ } } }, + "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:\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": { + "description": "Raw is the underlying serialization of this object.\n\nTODO: Determine how to detect ContentType and ContentEncoding of 'Raw' data.", + "type": "string", + "format": "byte" + } + } + }, "runtimeStreamError": { "type": "object", "properties": { @@ -5094,7 +5359,7 @@ "type": "string" }, "remainingItemCount": { - "type": "string", + "type": "integer", "format": "int64", "title": "remainingItemCount is the number of subsequent items in the list which are not included in this\nlist response. If the list request contained label or field selectors, then the number of\nremaining items is unknown and the field will be left unset and omitted during serialization.\nIf the list is complete (either because it is not chunking or because this is the last chunk),\nthen there are no more remaining items and this field will be left unset and omitted during\nserialization.\nServers older than v1.15 do not set this field.\nThe intended use of the remainingItemCount is *estimating* the size of a collection. Clients\nshould not rely on the remainingItemCount to be set or to be exact.\n+optional" }, @@ -5172,7 +5437,7 @@ }, "seconds": { "description": "Represents seconds of UTC time since Unix epoch\n1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to\n9999-12-31T23:59:59Z inclusive.", - "type": "string", + "type": "integer", "format": "int64" } } @@ -5234,15 +5499,11 @@ "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" }, "deletionGracePeriodSeconds": { - "type": "string", + "type": "integer", "format": "int64", "title": "Number of seconds allowed for this object to gracefully terminate before\nit will be removed from the system. Only set when deletionTimestamp is also set.\nMay only be shortened.\nRead-only.\n+optional" }, @@ -5261,7 +5522,7 @@ "type": "string" }, "generation": { - "type": "string", + "type": "integer", "format": "int64", "title": "A sequence number representing a specific generation of the desired state.\nPopulated by the system. Read-only.\n+optional" }, @@ -5309,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", @@ -5392,19 +5653,8 @@ }, "v1Time": { "description": "Time is a wrapper around time.Time which supports correct\nmarshaling to YAML and JSON. Wrappers are provided for many\nof the factory methods that the time package offers.\n\n+protobuf.options.marshal=false\n+protobuf.as=Timestamp\n+protobuf.options.(gogoproto.goproto_stringer)=false", - "type": "object", - "properties": { - "nanos": { - "description": "Non-negative fractions of a second at nanosecond resolution. Negative\nsecond values with fractions must still have non-negative nanos values\nthat count forward in time. Must be from 0 to 999,999,999\ninclusive. This field may be limited in precision depending on context.", - "type": "integer", - "format": "int32" - }, - "seconds": { - "description": "Represents seconds of UTC time since Unix epoch\n1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to\n9999-12-31T23:59:59Z inclusive.", - "type": "string", - "format": "int64" - } - } + "type": "string", + "format": "date-time" }, "v1alpha1AWSAuthConfig": { "type": "object", @@ -5414,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" @@ -5570,7 +5824,7 @@ }, "v1alpha1ApplicationCondition": { "type": "object", - "title": "ApplicationCondition contains details about an application condition, which is usally an error or warning", + "title": "ApplicationCondition contains details about an application condition, which is usually an error or warning", "properties": { "lastTransitionTime": { "$ref": "#/definitions/v1Time" @@ -5590,16 +5844,16 @@ "title": "ApplicationDestination holds information about the application's destination", "properties": { "name": { - "type": "string", - "title": "Name is an alternate way of specifying the target cluster by its symbolic name" + "description": "Name is an alternate way of specifying the target cluster by its symbolic name. This must be set if Server is not set.", + "type": "string" }, "namespace": { "type": "string", "title": "Namespace specifies the target namespace for the application's resources.\nThe namespace will only be set for namespace-scoped resources that have not set a value for .metadata.namespace" }, "server": { - "type": "string", - "title": "Server specifies the URL of the target cluster and must be set to the Kubernetes control plane API" + "description": "Server specifies the URL of the target cluster's Kubernetes control plane API. This must be set if Name is not set.", + "type": "string" } } }, @@ -5635,6 +5889,23 @@ } } }, + "v1alpha1ApplicationPreservedFields": { + "type": "object", + "properties": { + "annotations": { + "type": "array", + "items": { + "type": "string" + } + }, + "labels": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "v1alpha1ApplicationSet": { "type": "object", "title": "ApplicationSet is a set of Application resources\n+genclient\n+genclient:noStatus\n+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object\n+kubebuilder:resource:path=applicationsets,shortName=appset;appsets\n+kubebuilder:subresource:status", @@ -5668,6 +5939,10 @@ "status": { "type": "string", "title": "Status contains the AppSet's perceived status of the managed Application resource: (Waiting, Pending, Progressing, Healthy)" + }, + "step": { + "type": "string", + "title": "Step tracks which step this Application should be updated in" } } }, @@ -5718,6 +5993,9 @@ "merge": { "$ref": "#/definitions/v1alpha1MergeGenerator" }, + "plugin": { + "$ref": "#/definitions/v1alpha1PluginGenerator" + }, "pullRequest": { "$ref": "#/definitions/v1alpha1PullRequestGenerator" }, @@ -5766,6 +6044,9 @@ "merge": { "$ref": "#/definitions/v1JSON" }, + "plugin": { + "$ref": "#/definitions/v1alpha1PluginGenerator" + }, "pullRequest": { "$ref": "#/definitions/v1alpha1PullRequestGenerator" }, @@ -5777,6 +6058,30 @@ } } }, + "v1alpha1ApplicationSetResourceIgnoreDifferences": { + "description": "ApplicationSetResourceIgnoreDifferences configures how the ApplicationSet controller will ignore differences in live\napplications when applying changes from generated applications.", + "type": "object", + "properties": { + "jqPathExpressions": { + "description": "JQPathExpressions is a list of JQ path expressions to fields to ignore differences for.", + "type": "array", + "items": { + "type": "string" + } + }, + "jsonPointers": { + "description": "JSONPointers is a list of JSON pointers to fields to ignore differences for.", + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "description": "Name is the name of the application to ignore differences for. If not specified, the rule applies to all applications.", + "type": "string" + } + } + }, "v1alpha1ApplicationSetRolloutStep": { "type": "object", "properties": { @@ -5806,6 +6111,10 @@ "description": "ApplicationSetSpec represents a class of application set state.", "type": "object", "properties": { + "applyNestedSelectors": { + "type": "boolean", + "title": "ApplyNestedSelectors enables selectors defined within the generators of two level-nested matrix or merge generators" + }, "generators": { "type": "array", "items": { @@ -5815,6 +6124,21 @@ "goTemplate": { "type": "boolean" }, + "goTemplateOptions": { + "type": "array", + "items": { + "type": "string" + } + }, + "ignoreApplicationDifferences": { + "type": "array", + "items": { + "$ref": "#/definitions/v1alpha1ApplicationSetResourceIgnoreDifferences" + } + }, + "preservedFields": { + "$ref": "#/definitions/v1alpha1ApplicationPreservedFields" + }, "strategy": { "$ref": "#/definitions/v1alpha1ApplicationSetStrategy" }, @@ -5823,6 +6147,9 @@ }, "template": { "$ref": "#/definitions/v1alpha1ApplicationSetTemplate" + }, + "templatePatch": { + "type": "string" } } }, @@ -5861,6 +6188,10 @@ "description": "ApplicationSetSyncPolicy configures how generated Applications will relate to their\nApplicationSet.", "type": "object", "properties": { + "applicationsSync": { + "type": "string", + "title": "ApplicationsSync represents the policy applied on the generated applications. Possible values are create-only, create-update, create-delete, sync\n+kubebuilder:validation:Optional\n+kubebuilder:validation:Enum=create-only;create-update;create-delete;sync" + }, "preserveResourcesOnDeletion": { "description": "PreserveResourcesOnDeletion will preserve resources on deletion. If PreserveResourcesOnDeletion is set to true, these Applications will not be deleted.", "type": "boolean" @@ -6011,7 +6342,10 @@ }, "values": { "type": "string", - "title": "Values specifies Helm values to be passed to helm template, typically defined as a block" + "title": "Values specifies Helm values to be passed to helm template, typically defined as a block. ValuesObject takes precedence over Values, so use one or the other.\n+patchStrategy=replace" + }, + "valuesObject": { + "$ref": "#/definitions/runtimeRawExtension" }, "version": { "type": "string", @@ -6057,6 +6391,10 @@ "type": "string" } }, + "commonAnnotationsEnvsubst": { + "type": "boolean", + "title": "CommonAnnotationsEnvsubst specifies whether to apply env variables substitution for annotation values" + }, "commonLabels": { "type": "object", "title": "CommonLabels is a list of additional labels to add to rendered manifests", @@ -6064,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" @@ -6079,6 +6424,10 @@ "type": "string" } }, + "labelWithoutSelector": { + "type": "boolean", + "title": "LabelWithoutSelector specifies whether to apply common labels to resource selectors or not" + }, "namePrefix": { "type": "string", "title": "NamePrefix is a prefix appended to resources for Kustomize apps" @@ -6087,6 +6436,24 @@ "type": "string", "title": "NameSuffix is a suffix appended to resources for Kustomize apps" }, + "namespace": { + "type": "string", + "title": "Namespace sets the namespace that Kustomize adds to all resources" + }, + "patches": { + "type": "array", + "title": "Patches is a list of Kustomize patches", + "items": { + "$ref": "#/definitions/v1alpha1KustomizePatch" + } + }, + "replicas": { + "type": "array", + "title": "Replicas is a list of Kustomize Replicas override specifications", + "items": { + "$ref": "#/definitions/v1alpha1KustomizeReplica" + } + }, "version": { "type": "string", "title": "Version controls which version of Kustomize to use for rendering manifests" @@ -6168,7 +6535,7 @@ }, "revisionHistoryLimit": { "description": "RevisionHistoryLimit limits the number of items kept in the application's revision history, which is used for informational purposes as well as for rollbacks to previous versions.\nThis should only be changed in exceptional circumstances.\nSetting to zero will store no history. This will reduce storage used.\nIncreasing will increase the space used to store the history, so we do not recommend increasing it.\nDefault is 10.", - "type": "string", + "type": "integer", "format": "int64" }, "source": { @@ -6197,6 +6564,10 @@ "$ref": "#/definitions/v1alpha1ApplicationCondition" } }, + "controllerNamespace": { + "type": "string", + "title": "ControllerNamespace indicates the namespace in which the application controller is located" + }, "health": { "$ref": "#/definitions/v1alpha1HealthStatus" }, @@ -6314,7 +6685,7 @@ "title": "Duration is the amount to back off. Default unit is seconds, but could also be a duration (e.g. \"2m\", \"1h\")" }, "factor": { - "type": "string", + "type": "integer", "format": "int64", "title": "Factor is a factor to multiply the base duration after each failed retry" }, @@ -6337,6 +6708,35 @@ } } }, + "v1alpha1BearerTokenBitbucketCloud": { + "description": "BearerTokenBitbucketCloud defines the Bearer token for BitBucket AppToken auth.", + "type": "object", + "properties": { + "tokenRef": { + "$ref": "#/definitions/v1alpha1SecretRef" + } + } + }, + "v1alpha1ChartDetails": { + "type": "object", + "title": "ChartDetails contains helm chart metadata for a specific version", + "properties": { + "description": { + "type": "string" + }, + "home": { + "type": "string", + "title": "The URL of this projects home page, e.g. \"http://example.com\"" + }, + "maintainers": { + "type": "array", + "title": "List of maintainer details, name and email, e.g. [\"John Doe \"]", + "items": { + "type": "string" + } + } + } + }, "v1alpha1Cluster": { "type": "object", "title": "Cluster is the definition of a cluster resource", @@ -6396,7 +6796,7 @@ }, "shard": { "description": "Shard contains optional shard number. Calculated on the fly by the application controller if not specified.", - "type": "string", + "type": "integer", "format": "int64" } } @@ -6406,7 +6806,7 @@ "title": "ClusterCacheInfo contains information about the cluster cache", "properties": { "apisCount": { - "type": "string", + "type": "integer", "format": "int64", "title": "APIsCount holds number of observed Kubernetes API count" }, @@ -6414,7 +6814,7 @@ "$ref": "#/definitions/v1Time" }, "resourcesCount": { - "type": "string", + "type": "integer", "format": "int64", "title": "ResourcesCount holds number of observed Kubernetes resources" } @@ -6477,7 +6877,7 @@ } }, "applicationsCount": { - "type": "string", + "type": "integer", "format": "int64", "title": "ApplicationsCount is the number of applications managed by Argo CD on the cluster" }, @@ -6533,6 +6933,13 @@ "destination": { "$ref": "#/definitions/v1alpha1ApplicationDestination" }, + "ignoreDifferences": { + "type": "array", + "title": "IgnoreDifferences is a reference to the application's ignored differences used for comparison", + "items": { + "$ref": "#/definitions/v1alpha1ResourceIgnoreDifferences" + } + }, "source": { "$ref": "#/definitions/v1alpha1ApplicationSource" }, @@ -6595,7 +7002,7 @@ "type": "string" }, "requeueAfterSeconds": { - "type": "string", + "type": "integer", "format": "int64" }, "template": { @@ -6683,7 +7090,7 @@ "type": "string" }, "requeueAfterSeconds": { - "type": "string", + "type": "integer", "format": "int64" }, "revision": { @@ -6691,6 +7098,13 @@ }, "template": { "$ref": "#/definitions/v1alpha1ApplicationSetTemplate" + }, + "values": { + "type": "object", + "title": "Values contains key/value pairs which are passed directly as parameters to the template", + "additionalProperties": { + "type": "string" + } } } }, @@ -6808,15 +7222,15 @@ "title": "TODO: describe this type", "properties": { "capacity": { - "type": "string", + "type": "integer", "format": "int64" }, "requestedByApp": { - "type": "string", + "type": "integer", "format": "int64" }, "requestedByNeighbors": { - "type": "string", + "type": "integer", "format": "int64" }, "resourceName": { @@ -6854,11 +7268,11 @@ "title": "JWTToken holds the issuedAt and expiresAt values of a token", "properties": { "exp": { - "type": "string", + "type": "integer", "format": "int64" }, "iat": { - "type": "string", + "type": "integer", "format": "int64" }, "id": { @@ -6905,6 +7319,20 @@ } } }, + "v1alpha1KustomizeGvk": { + "type": "object", + "properties": { + "group": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, "v1alpha1KustomizeOptions": { "type": "object", "title": "KustomizeOptions are options for kustomize to use when building manifests", @@ -6919,16 +7347,80 @@ } } }, + "v1alpha1KustomizePatch": { + "type": "object", + "properties": { + "options": { + "type": "object", + "additionalProperties": { + "type": "boolean" + } + }, + "patch": { + "type": "string" + }, + "path": { + "type": "string" + }, + "target": { + "$ref": "#/definitions/v1alpha1KustomizeSelector" + } + } + }, + "v1alpha1KustomizeReplica": { + "type": "object", + "properties": { + "count": { + "$ref": "#/definitions/intstrIntOrString" + }, + "name": { + "type": "string", + "title": "Name of Deployment or StatefulSet" + } + } + }, + "v1alpha1KustomizeResId": { + "type": "object", + "properties": { + "gvk": { + "$ref": "#/definitions/v1alpha1KustomizeGvk" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + } + } + }, + "v1alpha1KustomizeSelector": { + "type": "object", + "properties": { + "annotationSelector": { + "type": "string" + }, + "labelSelector": { + "type": "string" + }, + "resId": { + "$ref": "#/definitions/v1alpha1KustomizeResId" + } + } + }, "v1alpha1ListGenerator": { "type": "object", "title": "ListGenerator include items info", "properties": { "elements": { "type": "array", + "title": "+kubebuilder:validation:Optional", "items": { "$ref": "#/definitions/v1JSON" } }, + "elementsYaml": { + "type": "string" + }, "template": { "$ref": "#/definitions/v1alpha1ApplicationSetTemplate" } @@ -7042,7 +7534,7 @@ "title": "Phase is the current phase of the operation" }, "retryCount": { - "type": "string", + "type": "integer", "format": "int64", "title": "RetryCount contains time of operation retries" }, @@ -7113,6 +7605,54 @@ } } }, + "v1alpha1PluginConfigMapRef": { + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Name of the ConfigMap" + } + } + }, + "v1alpha1PluginGenerator": { + "description": "PluginGenerator defines connection info specific to Plugin.", + "type": "object", + "properties": { + "configMapRef": { + "$ref": "#/definitions/v1alpha1PluginConfigMapRef" + }, + "input": { + "$ref": "#/definitions/v1alpha1PluginInput" + }, + "requeueAfterSeconds": { + "description": "RequeueAfterSeconds determines how long the ApplicationSet controller will wait before reconciling the ApplicationSet again.", + "type": "integer", + "format": "int64" + }, + "template": { + "$ref": "#/definitions/v1alpha1ApplicationSetTemplate" + }, + "values": { + "description": "Values contains key/value pairs which are passed directly as parameters to the template. These values will not be\nsent as parameters to the plugin.", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "v1alpha1PluginInput": { + "type": "object", + "properties": { + "parameters": { + "description": "Parameters contains the information to pass to the plugin. It is a map. The keys must be strings, and the\nvalues can be any type.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/v1JSON" + } + } + } + }, "v1alpha1ProjectRole": { "type": "object", "title": "ProjectRole represents a role that has access to a project", @@ -7152,6 +7692,12 @@ "description": "PullRequestGenerator defines a generator that scrapes a PullRequest API to find candidate pull requests.", "type": "object", "properties": { + "azuredevops": { + "$ref": "#/definitions/v1alpha1PullRequestGeneratorAzureDevOps" + }, + "bitbucket": { + "$ref": "#/definitions/v1alpha1PullRequestGeneratorBitbucket" + }, "bitbucketServer": { "$ref": "#/definitions/v1alpha1PullRequestGeneratorBitbucketServer" }, @@ -7173,7 +7719,7 @@ }, "requeueAfterSeconds": { "description": "Standard parameters.", - "type": "string", + "type": "integer", "format": "int64" }, "template": { @@ -7181,8 +7727,64 @@ } } }, + "v1alpha1PullRequestGeneratorAzureDevOps": { + "description": "PullRequestGeneratorAzureDevOps defines connection info specific to AzureDevOps.", + "type": "object", + "properties": { + "api": { + "description": "The Azure DevOps API URL to talk to. If blank, use https://dev.azure.com/.", + "type": "string" + }, + "labels": { + "type": "array", + "title": "Labels is used to filter the PRs that you want to target", + "items": { + "type": "string" + } + }, + "organization": { + "description": "Azure DevOps org to scan. Required.", + "type": "string" + }, + "project": { + "description": "Azure DevOps project name to scan. Required.", + "type": "string" + }, + "repo": { + "description": "Azure DevOps repo name to scan. Required.", + "type": "string" + }, + "tokenRef": { + "$ref": "#/definitions/v1alpha1SecretRef" + } + } + }, + "v1alpha1PullRequestGeneratorBitbucket": { + "description": "PullRequestGeneratorBitbucket defines connection info specific to Bitbucket.", + "type": "object", + "properties": { + "api": { + "description": "The Bitbucket REST API URL to talk to. If blank, uses https://api.bitbucket.org/2.0.", + "type": "string" + }, + "basicAuth": { + "$ref": "#/definitions/v1alpha1BasicAuthBitbucketServer" + }, + "bearerToken": { + "$ref": "#/definitions/v1alpha1BearerTokenBitbucketCloud" + }, + "owner": { + "description": "Workspace to scan. Required.", + "type": "string" + }, + "repo": { + "description": "Repo name to scan. Required.", + "type": "string" + } + } + }, "v1alpha1PullRequestGeneratorBitbucketServer": { - "description": "PullRequestGenerator defines connection info specific to BitbucketServer.", + "description": "PullRequestGeneratorBitbucketServer defines connection info specific to BitbucketServer.", "type": "object", "properties": { "api": { @@ -7208,6 +7810,9 @@ "properties": { "branchMatch": { "type": "string" + }, + "targetBranchMatch": { + "type": "string" } } }, @@ -7219,6 +7824,10 @@ "description": "The GitLab API URL to talk to. If blank, uses https://gitlab.com/.", "type": "string" }, + "insecure": { + "type": "boolean", + "title": "Skips validating the SCM provider's TLS certificate - useful for self-signed certificates.; default: false" + }, "labels": { "type": "array", "title": "Labels is used to filter the MRs that you want to target", @@ -7240,7 +7849,7 @@ } }, "v1alpha1PullRequestGeneratorGitea": { - "description": "PullRequestGenerator defines connection info specific to Gitea.", + "description": "PullRequestGeneratorGitea defines connection info specific to Gitea.", "type": "object", "properties": { "api": { @@ -7304,6 +7913,10 @@ "type": "boolean", "title": "EnableOCI specifies whether helm-oci support should be enabled for this repo" }, + "forceHttpBasicAuth": { + "type": "boolean", + "title": "ForceHttpBasicAuth specifies whether Argo CD should attempt to force basic auth for HTTP connections" + }, "gcpServiceAccountKey": { "type": "string", "title": "GCPServiceAccountKey specifies the service account key in JSON format to be used for getting credentials to Google Cloud Source repos" @@ -7313,12 +7926,12 @@ "title": "GithubAppEnterpriseBaseURL specifies the GitHub API URL for GitHub app authentication. If empty will default to https://api.github.com" }, "githubAppID": { - "type": "string", + "type": "integer", "format": "int64", "title": "GithubAppId specifies the Github App ID of the app used to access the repo for GitHub app authentication" }, "githubAppInstallationID": { - "type": "string", + "type": "integer", "format": "int64", "title": "GithubAppInstallationId specifies the ID of the installed GitHub App for GitHub app authentication" }, @@ -7390,6 +8003,10 @@ "type": "boolean", "title": "EnableOCI specifies whether helm-oci support should be enabled for this repo" }, + "forceHttpBasicAuth": { + "type": "boolean", + "title": "ForceHttpBasicAuth specifies whether Argo CD should attempt to force basic auth for HTTP connections" + }, "gcpServiceAccountKey": { "type": "string", "title": "GCPServiceAccountKey specifies the service account key in JSON format to be used for getting credentials to Google Cloud Source repos" @@ -7399,12 +8016,12 @@ "title": "GithubAppEnterpriseBaseURL specifies the base URL of GitHub Enterprise installation. If empty will default to https://api.github.com" }, "githubAppID": { - "type": "string", + "type": "integer", "format": "int64", "title": "GithubAppId specifies the ID of the GitHub app used to access the repo" }, "githubAppInstallationID": { - "type": "string", + "type": "integer", "format": "int64", "title": "GithubAppInstallationId specifies the installation ID of the GitHub App used to access the repo" }, @@ -7531,6 +8148,12 @@ "disabled": { "type": "boolean" }, + "displayName": { + "type": "string" + }, + "iconClass": { + "type": "string" + }, "name": { "type": "string" }, @@ -7712,13 +8335,15 @@ "$ref": "#/definitions/v1alpha1ResourceRef" } }, - "resourceRef": { - "$ref": "#/definitions/v1alpha1ResourceRef" - }, "resourceVersion": { "type": "string" } - } + }, + "allOf": [ + { + "$ref": "#/definitions/v1alpha1ResourceRef" + } + ] }, "v1alpha1ResourceOverride": { "type": "object", @@ -7733,6 +8358,9 @@ "ignoreDifferences": { "$ref": "#/definitions/v1alpha1OverrideIgnoreDiff" }, + "ignoreResourceUpdates": { + "$ref": "#/definitions/v1alpha1OverrideIgnoreDiff" + }, "knownTypeFields": { "type": "array", "items": { @@ -7843,7 +8471,7 @@ "type": "string" }, "syncWave": { - "type": "string", + "type": "integer", "format": "int64" }, "version": { @@ -7860,7 +8488,7 @@ }, "limit": { "description": "Limit is the maximum number of attempts for retrying a failed sync. If set to 0, no retries will be performed.", - "type": "string", + "type": "integer", "format": "int64" } } @@ -7876,10 +8504,13 @@ "$ref": "#/definitions/v1Time" }, "id": { - "type": "string", + "type": "integer", "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" @@ -7935,6 +8566,9 @@ "description": "SCMProviderGenerator defines a generator that scrapes a SCMaaS API to find candidate repos.", "type": "object", "properties": { + "awsCodeCommit": { + "$ref": "#/definitions/v1alpha1SCMProviderGeneratorAWSCodeCommit" + }, "azureDevOps": { "$ref": "#/definitions/v1alpha1SCMProviderGeneratorAzureDevOps" }, @@ -7966,11 +8600,43 @@ }, "requeueAfterSeconds": { "description": "Standard parameters.", - "type": "string", + "type": "integer", "format": "int64" }, "template": { "$ref": "#/definitions/v1alpha1ApplicationSetTemplate" + }, + "values": { + "type": "object", + "title": "Values contains key/value pairs which are passed directly as parameters to the template", + "additionalProperties": { + "type": "string" + } + } + } + }, + "v1alpha1SCMProviderGeneratorAWSCodeCommit": { + "description": "SCMProviderGeneratorAWSCodeCommit defines connection info specific to AWS CodeCommit.", + "type": "object", + "properties": { + "allBranches": { + "description": "Scan all branches instead of just the default branch.", + "type": "boolean" + }, + "region": { + "description": "Region provides the AWS region to discover repos.\nif not provided, AppSet controller will infer the current region from environment.", + "type": "string" + }, + "role": { + "description": "Role provides the AWS IAM role to assume, for cross-account repo discovery\nif not provided, AppSet controller will use its pod/node identity to discover.", + "type": "string" + }, + "tagFilters": { + "type": "array", + "title": "TagFilters provides the tag filter(s) for repo discovery", + "items": { + "$ref": "#/definitions/v1alpha1TagFilter" + } } } }, @@ -8139,12 +8805,24 @@ "description": "Gitlab group to scan. Required. You can use either the project id (recommended) or the full namespaced path.", "type": "string" }, + "includeSharedProjects": { + "type": "boolean", + "title": "When recursing through subgroups, also include shared Projects (true) or scan only the subgroups under same path (false). Defaults to \"true\"" + }, "includeSubgroups": { "type": "boolean", "title": "Recurse through subgroups (true) or scan only the base group (false). Defaults to \"false\"" }, + "insecure": { + "type": "boolean", + "title": "Skips validating the SCM provider's TLS certificate - useful for self-signed certificates.; default: false" + }, "tokenRef": { "$ref": "#/definitions/v1alpha1SecretRef" + }, + "topic": { + "description": "Filter repos list based on Gitlab Topic.", + "type": "string" } } }, @@ -8251,6 +8929,9 @@ "type": "object", "title": "SyncOperationResult represent result of sync operation", "properties": { + "managedNamespaceMetadata": { + "$ref": "#/definitions/v1alpha1ManagedNamespaceMetadata" + }, "resources": { "type": "array", "title": "Resources contains a list of sync result items for each individual resource in a sync operation", @@ -8317,7 +8998,7 @@ }, "selfHeal": { "type": "boolean", - "title": "SelfHeal specifes whether to revert resources back to their desired state upon modification in the cluster (default: false)" + "title": "SelfHeal specifies whether to revert resources back to their desired state upon modification in the cluster (default: false)" } } }, @@ -8452,6 +9133,17 @@ } } }, + "v1alpha1TagFilter": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "versionVersionMessage": { "type": "object", "title": "VersionMessage represents version of the Argo CD API server", @@ -8462,6 +9154,9 @@ "Compiler": { "type": "string" }, + "ExtraBuildInfo": { + "type": "string" + }, "GitCommit": { "type": "string" }, diff --git a/cmd/argocd-application-controller/commands/argocd_application_controller.go b/cmd/argocd-application-controller/commands/argocd_application_controller.go index 1d94fa64d42d2..3c7fe8bbac107 100644 --- a/cmd/argocd-application-controller/commands/argocd_application_controller.go +++ b/cmd/argocd-application-controller/commands/argocd_application_controller.go @@ -7,7 +7,7 @@ import ( "time" "github.com/argoproj/pkg/stats" - "github.com/go-redis/redis/v8" + "github.com/redis/go-redis/v9" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "k8s.io/client-go/kubernetes" @@ -19,6 +19,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" @@ -33,7 +34,7 @@ import ( const ( // CLIName is the name of the CLI - cliName = "argocd-application-controller" + cliName = common.ApplicationController // Default time in seconds for application resync period defaultAppResyncPeriod = 180 // Default time in seconds for application hard resync period @@ -42,26 +43,35 @@ const ( func NewCommand() *cobra.Command { var ( - clientConfig clientcmd.ClientConfig - appResyncPeriod int64 - appHardResyncPeriod int64 - repoServerAddress string - repoServerTimeoutSeconds int - selfHealTimeoutSeconds int - statusProcessors int - operationProcessors int - glogLevel int - metricsPort int - metricsCacheExpiration time.Duration - metricsAplicationLabels []string - kubectlParallelismLimit int64 - cacheSrc func() (*appstatecache.Cache, error) - redisClient *redis.Client - repoServerPlaintext bool - repoServerStrictTLS bool - otlpAddress string - applicationNamespaces []string - persistResourceHealth bool + workqueueRateLimit ratelimiter.AppControllerRateLimiterConfig + clientConfig clientcmd.ClientConfig + appResyncPeriod int64 + appHardResyncPeriod int64 + appResyncJitter int64 + repoErrorGracePeriod int64 + repoServerAddress string + repoServerTimeoutSeconds int + selfHealTimeoutSeconds int + statusProcessors int + operationProcessors int + glogLevel int + metricsPort int + metricsCacheExpiration time.Duration + metricsAplicationLabels []string + kubectlParallelismLimit int64 + cacheSource func() (*appstatecache.Cache, error) + redisClient *redis.Client + 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, @@ -89,7 +99,7 @@ func NewCommand() *cobra.Command { config, err := clientConfig.ClientConfig() errors.CheckError(err) errors.CheckError(v1alpha1.SetK8SConfigDefaults(config)) - config.UserAgent = fmt.Sprintf("argocd-application-controller/%s (%s)", vers.Version, vers.Platform) + config.UserAgent = fmt.Sprintf("%s/%s (%s)", common.DefaultApplicationControllerName, vers.Version, vers.Platform) kubeClient := kubernetes.NewForConfigOrDie(config) appClient := appclientset.NewForConfigOrDie(config) @@ -124,7 +134,7 @@ func NewCommand() *cobra.Command { repoClientset := apiclient.NewRepoServerClientset(repoServerAddress, repoServerTimeoutSeconds, tlsConfig) - cache, err := cacheSrc() + cache, err := cacheSource() errors.CheckError(err) cache.Cache.SetClient(cacheutil.NewTwoLevelClient(cache.Cache.GetClient(), 10*time.Minute)) @@ -134,7 +144,8 @@ func NewCommand() *cobra.Command { appController.InvalidateProjectsCache() })) kubectl := kubeutil.NewKubectl() - clusterFilter := getClusterFilter() + clusterSharding, err := sharding.GetClusterSharding(kubeClient, settingsMgr, shardingAlgorithm, enableDynamicClusterDistribution) + errors.CheckError(err) appController, err = controller.NewApplicationController( namespace, settingsMgr, @@ -145,14 +156,20 @@ 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, - applicationNamespaces) + clusterSharding, + applicationNamespaces, + &workqueueRateLimit, + serverSideDiff, + enableDynamicClusterDistribution, + ) errors.CheckError(err) cacheutil.CollectMetrics(redisClient, appController.GetMetricsServer()) @@ -161,7 +178,7 @@ func NewCommand() *cobra.Command { stats.RegisterHeapDumper("memprofile") if otlpAddress != "" { - closeTracer, err := trace.InitTracer(ctx, "argocd-controller", otlpAddress) + closeTracer, err := trace.InitTracer(ctx, "argocd-controller", otlpAddress, otlpInsecure, otlpHeaders, otlpAttrs) if err != nil { log.Fatalf("failed to initialize tracing: %v", err) } @@ -178,6 +195,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") @@ -188,33 +207,32 @@ func NewCommand() *cobra.Command { command.Flags().IntVar(&metricsPort, "metrics-port", common.DefaultPortArgoCDMetrics, "Start metrics server on given port") command.Flags().DurationVar(&metricsCacheExpiration, "metrics-cache-expiration", env.ParseDurationFromEnv("ARGOCD_APPLICATION_CONTROLLER_METRICS_CACHE_EXPIRATION", 0*time.Second, 0, math.MaxInt64), "Prometheus metrics cache expiration (disabled by default. e.g. 24h0m0s)") command.Flags().IntVar(&selfHealTimeoutSeconds, "self-heal-timeout-seconds", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_TIMEOUT_SECONDS", 5, 0, math.MaxInt32), "Specifies timeout between application self heal attempts") - command.Flags().Int64Var(&kubectlParallelismLimit, "kubectl-parallelism-limit", 20, "Number of allowed concurrent kubectl fork/execs. Any value less the 1 means no limit.") + command.Flags().Int64Var(&kubectlParallelismLimit, "kubectl-parallelism-limit", env.ParseInt64FromEnv("ARGOCD_APPLICATION_CONTROLLER_KUBECTL_PARALLELISM_LIMIT", 20, 0, math.MaxInt64), "Number of allowed concurrent kubectl fork/execs. Any value less than 1 means no limit.") command.Flags().BoolVar(&repoServerPlaintext, "repo-server-plaintext", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT", false), "Disable TLS on connections to repo server") 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") - cacheSrc = appstatecache.AddCacheFlagsToCmd(&command, func(client *redis.Client) { - redisClient = client + 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().Float64Var(&workqueueRateLimit.BucketQPS, "wq-bucket-qps", env.ParseFloat64FromEnv("WORKQUEUE_BUCKET_QPS", math.MaxFloat64, 1, math.MaxFloat64), "Set Workqueue Rate Limiter Bucket QPS, default set to MaxFloat64 which disables the bucket limiter") + // 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.") + 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() func(cluster *v1alpha1.Cluster) bool { - replicas := env.ParseNumFromEnv(common.EnvControllerReplicas, 0, 0, math.MaxInt32) - shard := env.ParseNumFromEnv(common.EnvControllerShard, -1, -math.MaxInt32, math.MaxInt32) - var clusterFilter func(cluster *v1alpha1.Cluster) bool - if replicas > 1 { - if shard < 0 { - var err error - shard, err = sharding.InferShard() - errors.CheckError(err) - } - log.Infof("Processing clusters from shard %d", shard) - clusterFilter = sharding.GetClusterFilter(replicas, shard) - } else { - log.Info("Processing all cluster shards") - } - return clusterFilter -} diff --git a/cmd/argocd-applicationset-controller/commands/applicationset_controller.go b/cmd/argocd-applicationset-controller/commands/applicationset_controller.go index fa64a0f680940..9adbc3e64a685 100644 --- a/cmd/argocd-applicationset-controller/commands/applicationset_controller.go +++ b/cmd/argocd-applicationset-controller/commands/applicationset_controller.go @@ -2,6 +2,7 @@ package command import ( "fmt" + "math" "net/http" "os" "time" @@ -9,7 +10,9 @@ import ( "github.com/argoproj/pkg/stats" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/cache" + + "github.com/argoproj/argo-cd/v2/reposerver/apiclient" + "github.com/argoproj/argo-cd/v2/util/tls" "github.com/argoproj/argo-cd/v2/applicationset/controllers" "github.com/argoproj/argo-cd/v2/applicationset/generators" @@ -17,7 +20,6 @@ import ( "github.com/argoproj/argo-cd/v2/applicationset/webhook" cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" "github.com/argoproj/argo-cd/v2/common" - "github.com/argoproj/argo-cd/v2/reposerver/askpass" "github.com/argoproj/argo-cd/v2/util/env" "github.com/argoproj/argo-cd/v2/util/github_app" @@ -30,7 +32,6 @@ import ( "k8s.io/client-go/tools/clientcmd" "github.com/argoproj/argo-cd/v2/applicationset/services" - appsetv1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" appv1alpha1 "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/util/cli" @@ -39,28 +40,35 @@ import ( argosettings "github.com/argoproj/argo-cd/v2/util/settings" ) -// TODO: load this using Cobra. -func getSubmoduleEnabled() bool { - return env.ParseBoolFromEnv(common.EnvGitSubmoduleEnabled, true) -} +var gitSubmoduleEnabled = env.ParseBoolFromEnv(common.EnvGitSubmoduleEnabled, true) func NewCommand() *cobra.Command { var ( - clientConfig clientcmd.ClientConfig - metricsAddr string - probeBindAddr string - webhookAddr string - enableLeaderElection bool - namespace string - argocdRepoServer string - policy string - debugLog bool - dryRun bool - enableProgressiveRollouts bool + clientConfig clientcmd.ClientConfig + metricsAddr string + probeBindAddr string + webhookAddr string + enableLeaderElection bool + applicationSetNamespaces []string + argocdRepoServer string + policy string + enablePolicyOverride bool + debugLog bool + dryRun bool + enableProgressiveSyncs bool + enableNewGitFileGlobbing bool + repoServerPlaintext bool + repoServerStrictTLS bool + repoServerTimeoutSeconds int + maxConcurrentReconciliations int + scmRootCAPath string + allowedScmProviders []string + globalPreservedAnnotations []string + globalPreservedLabels []string + enableScmProviders bool ) scheme := runtime.NewScheme() _ = clientgoscheme.AddToScheme(scheme) - _ = appsetv1alpha1.AddToScheme(scheme) _ = appv1alpha1.AddToScheme(scheme) var command = cobra.Command{ Use: "controller", @@ -70,6 +78,8 @@ func NewCommand() *cobra.Command { vers := common.GetVersion() namespace, _, err := clientConfig.Namespace() + applicationSetNamespaces = append(applicationSetNamespaces, namespace) + errors.CheckError(err) vers.LogStartupInfo( "ArgoCD ApplicationSet Controller", @@ -82,58 +92,81 @@ func NewCommand() *cobra.Command { cli.SetLogLevel(cmdutil.LogLevel) restConfig, err := clientConfig.ClientConfig() - if err != nil { - return err - } + errors.CheckError(err) restConfig.UserAgent = fmt.Sprintf("argocd-applicationset-controller/%s (%s)", vers.Version, vers.Platform) policyObj, exists := utils.Policies[policy] if !exists { - log.Info("Policy value can be: sync, create-only, create-update, create-delete") + log.Error("Policy value can be: sync, create-only, create-update, create-delete, default value: sync") + os.Exit(1) + } + + // By default watch all namespace + var watchedNamespace string = "" + + // If the applicationset-namespaces contains only one namespace it corresponds to the current namespace + if len(applicationSetNamespaces) == 1 { + watchedNamespace = (applicationSetNamespaces)[0] + } else if enableScmProviders && len(allowedScmProviders) == 0 { + log.Error("When enabling applicationset in any namespace using applicationset-namespaces, you must either set --enable-scm-providers=false or specify --allowed-scm-providers") os.Exit(1) } mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - MetricsBindAddress: metricsAddr, - // Our cache and thus watches and client queries are restricted to the namespace we're running in. This assumes - // the applicationset controller is in the same namespace as argocd, which should be the same namespace of - // all cluster Secrets and Applications we interact with. - NewCache: cache.MultiNamespacedCacheBuilder([]string{namespace}), + Scheme: scheme, + MetricsBindAddress: metricsAddr, + Namespace: watchedNamespace, HealthProbeBindAddress: probeBindAddr, Port: 9443, LeaderElection: enableLeaderElection, LeaderElectionID: "58ac56fa.applicationsets.argoproj.io", DryRunClient: dryRun, }) + if err != nil { log.Error(err, "unable to start manager") os.Exit(1) } dynamicClient, err := dynamic.NewForConfig(mgr.GetConfig()) - if err != nil { - return err - } + errors.CheckError(err) k8sClient, err := kubernetes.NewForConfig(mgr.GetConfig()) - if err != nil { - return err - } + errors.CheckError(err) + argoSettingsMgr := argosettings.NewSettingsManager(ctx, k8sClient, namespace) appSetConfig := appclientset.NewForConfigOrDie(mgr.GetConfig()) argoCDDB := db.NewDB(namespace, argoSettingsMgr, k8sClient) - askPassServer := askpass.NewServer() scmAuth := generators.SCMAuthProviders{ GitHubApps: github_app.NewAuthCredentials(argoCDDB.(db.RepoCredsDB)), } + + tlsConfig := apiclient.TLSConfiguration{ + DisableTLS: repoServerPlaintext, + StrictValidation: repoServerPlaintext, + } + + if !repoServerPlaintext && repoServerStrictTLS { + pool, err := tls.LoadX509CertPool( + fmt.Sprintf("%s/reposerver/tls/tls.crt", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath)), + fmt.Sprintf("%s/reposerver/tls/ca.crt", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath)), + ) + errors.CheckError(err) + tlsConfig.Certificates = pool + } + + repoClientset := apiclient.NewRepoServerClientset(argocdRepoServer, repoServerTimeoutSeconds, tlsConfig) + argoCDService, err := services.NewArgoCDService(argoCDDB, gitSubmoduleEnabled, repoClientset, enableNewGitFileGlobbing) + errors.CheckError(err) + terminalGenerators := map[string]generators.Generator{ "List": generators.NewListGenerator(), "Clusters": generators.NewClusterGenerator(mgr.GetClient(), ctx, k8sClient, namespace), - "Git": generators.NewGitGenerator(services.NewArgoCDService(argoCDDB, askPassServer, getSubmoduleEnabled())), - "SCMProvider": generators.NewSCMProviderGenerator(mgr.GetClient(), scmAuth), + "Git": generators.NewGitGenerator(argoCDService), + "SCMProvider": generators.NewSCMProviderGenerator(mgr.GetClient(), scmAuth, scmRootCAPath, allowedScmProviders, enableScmProviders), "ClusterDecisionResource": generators.NewDuckTypeGenerator(ctx, dynamicClient, k8sClient, namespace), - "PullRequest": generators.NewPullRequestGenerator(mgr.GetClient(), scmAuth), + "PullRequest": generators.NewPullRequestGenerator(mgr.GetClient(), scmAuth, scmRootCAPath, allowedScmProviders, enableScmProviders), + "Plugin": generators.NewPluginGenerator(mgr.GetClient(), ctx, k8sClient, namespace), } nestedGenerators := map[string]generators.Generator{ @@ -143,6 +176,7 @@ func NewCommand() *cobra.Command { "SCMProvider": terminalGenerators["SCMProvider"], "ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"], "PullRequest": terminalGenerators["PullRequest"], + "Plugin": terminalGenerators["Plugin"], "Matrix": generators.NewMatrixGenerator(terminalGenerators), "Merge": generators.NewMergeGenerator(terminalGenerators), } @@ -154,6 +188,7 @@ func NewCommand() *cobra.Command { "SCMProvider": terminalGenerators["SCMProvider"], "ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"], "PullRequest": terminalGenerators["PullRequest"], + "Plugin": terminalGenerators["Plugin"], "Matrix": generators.NewMatrixGenerator(nestedGenerators), "Merge": generators.NewMergeGenerator(nestedGenerators), } @@ -167,19 +202,25 @@ func NewCommand() *cobra.Command { startWebhookServer(webhookHandler, webhookAddr) } - go func() { errors.CheckError(askPassServer.Run(askpass.SocketPath)) }() if err = (&controllers.ApplicationSetReconciler{ - Generators: topLevelGenerators, - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - Recorder: mgr.GetEventRecorderFor("applicationset-controller"), - Renderer: &utils.Render{}, - Policy: policyObj, - ArgoAppClientset: appSetConfig, - KubeClientset: k8sClient, - ArgoDB: argoCDDB, - EnableProgressiveRollouts: enableProgressiveRollouts, - }).SetupWithManager(mgr); err != nil { + Generators: topLevelGenerators, + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + Recorder: mgr.GetEventRecorderFor("applicationset-controller"), + Renderer: &utils.Render{}, + Policy: policyObj, + EnablePolicyOverride: enablePolicyOverride, + ArgoAppClientset: appSetConfig, + KubeClientset: k8sClient, + ArgoDB: argoCDDB, + ArgoCDNamespace: namespace, + ApplicationSetNamespaces: applicationSetNamespaces, + EnableProgressiveSyncs: enableProgressiveSyncs, + SCMRootCAPath: scmRootCAPath, + GlobalPreservedAnnotations: globalPreservedAnnotations, + GlobalPreservedLabels: globalPreservedLabels, + Cache: mgr.GetCache(), + }).SetupWithManager(mgr, enableProgressiveSyncs, maxConcurrentReconciliations); err != nil { log.Error(err, "unable to create controller", "controller", "ApplicationSet") os.Exit(1) } @@ -200,14 +241,25 @@ func NewCommand() *cobra.Command { command.Flags().BoolVar(&enableLeaderElection, "enable-leader-election", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_LEADER_ELECTION", false), "Enable leader election for controller manager. "+ "Enabling this will ensure there is only one active controller manager.") - command.Flags().StringVar(&namespace, "namespace", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACE", ""), "Argo CD repo namespace (default: argocd)") + command.Flags().StringSliceVar(&applicationSetNamespaces, "applicationset-namespaces", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES", []string{}, ","), "Argo CD applicationset namespaces") command.Flags().StringVar(&argocdRepoServer, "argocd-repo-server", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER", common.DefaultRepoServerAddr), "Argo CD repo server address") - command.Flags().StringVar(&policy, "policy", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_POLICY", "sync"), "Modify how application is synced between the generator and the cluster. Default is 'sync' (create & update & delete), options: 'create-only', 'create-update' (no deletion), 'create-delete' (no update)") + command.Flags().StringVar(&policy, "policy", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_POLICY", ""), "Modify how application is synced between the generator and the cluster. Default is 'sync' (create & update & delete), options: 'create-only', 'create-update' (no deletion), 'create-delete' (no update)") + command.Flags().BoolVar(&enablePolicyOverride, "enable-policy-override", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE", policy == ""), "For security reason if 'policy' is set, it is not possible to override it at applicationSet level. 'allow-policy-override' allows user to define their own policy") command.Flags().BoolVar(&debugLog, "debug", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG", false), "Print debug logs. Takes precedence over loglevel") command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGFORMAT", "text"), "Set the logging format. One of: text|json") command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error") + command.Flags().StringSliceVar(&allowedScmProviders, "allowed-scm-providers", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS", []string{}, ","), "The list of allowed custom SCM provider API URLs. This restriction does not apply to SCM or PR generators which do not accept a custom API URL. (Default: Empty = all)") + command.Flags().BoolVar(&enableScmProviders, "enable-scm-providers", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS", true), "Enable retrieving information from SCM providers, used by the SCM and PR generators (Default: true)") command.Flags().BoolVar(&dryRun, "dry-run", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_DRY_RUN", false), "Enable dry run mode") - command.Flags().BoolVar(&enableProgressiveRollouts, "enable-progressive-rollouts", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS", false), "Enable use of the experimental progressive rollouts feature.") + command.Flags().BoolVar(&enableProgressiveSyncs, "enable-progressive-syncs", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS", false), "Enable use of the experimental progressive syncs feature.") + command.Flags().BoolVar(&enableNewGitFileGlobbing, "enable-new-git-file-globbing", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING", false), "Enable new globbing in Git files generator.") + command.Flags().BoolVar(&repoServerPlaintext, "repo-server-plaintext", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT", false), "Disable TLS on connections to repo server") + command.Flags().BoolVar(&repoServerStrictTLS, "repo-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_STRICT_TLS", false), "Whether to use strict validation of the TLS cert presented by the repo server") + command.Flags().IntVar(&repoServerTimeoutSeconds, "repo-server-timeout-seconds", env.ParseNumFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS", 60, 0, math.MaxInt64), "Repo server RPC call timeout seconds.") + command.Flags().IntVar(&maxConcurrentReconciliations, "concurrent-reconciliations", env.ParseNumFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_CONCURRENT_RECONCILIATIONS", 10, 1, 100), "Max concurrent reconciliations limit for the controller") + command.Flags().StringVar(&scmRootCAPath, "scm-root-ca-path", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH", ""), "Provide Root CA Path for self-signed TLS Certificates") + command.Flags().StringSliceVar(&globalPreservedAnnotations, "preserved-annotations", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_ANNOTATIONS", []string{}, ","), "Sets global preserved field values for annotations") + command.Flags().StringSliceVar(&globalPreservedLabels, "preserved-labels", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_LABELS", []string{}, ","), "Sets global preserved field values for labels") return &command } diff --git a/cmd/argocd-cmp-server/commands/argocd_cmp_server.go b/cmd/argocd-cmp-server/commands/argocd_cmp_server.go index ffb5eccc2f450..526a199cb5490 100644 --- a/cmd/argocd-cmp-server/commands/argocd_cmp_server.go +++ b/cmd/argocd-cmp-server/commands/argocd_cmp_server.go @@ -26,11 +26,14 @@ func NewCommand() *cobra.Command { var ( configFilePath string otlpAddress string + otlpInsecure bool + otlpHeaders map[string]string + otlpAttrs []string ) var command = cobra.Command{ Use: cliName, Short: "Run ArgoCD ConfigManagementPlugin Server", - Long: "ArgoCD ConfigManagementPlugin Server is an internal service which runs as sidecar container in reposerver deployment. It can be configured by following options.", + Long: "ArgoCD ConfigManagementPlugin Server is an internal service which runs as sidecar container in reposerver deployment. The following configuration options are available:", DisableAutoGenTag: true, RunE: func(c *cobra.Command, args []string) error { ctx := c.Context() @@ -44,10 +47,18 @@ func NewCommand() *cobra.Command { config, err := plugin.ReadPluginConfig(configFilePath) errors.CheckError(err) + if !config.Spec.Discover.IsDefined() { + name := config.Metadata.Name + if config.Spec.Version != "" { + name = name + "-" + config.Spec.Version + } + log.Infof("No discovery configuration is defined for plugin %s. To use this plugin, specify %q in the Application's spec.source.plugin.name field.", config.Metadata.Name, name) + } + if otlpAddress != "" { var closer func() var err error - closer, err = traceutil.InitTracer(ctx, "argocd-cmp-server", otlpAddress) + closer, err = traceutil.InitTracer(ctx, "argocd-cmp-server", otlpAddress, otlpInsecure, otlpHeaders, otlpAttrs) if err != nil { log.Fatalf("failed to initialize tracing: %v", err) } @@ -74,5 +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-dex/commands/argocd_dex.go b/cmd/argocd-dex/commands/argocd_dex.go index 7d9f04c31f553..2b070ec895e41 100644 --- a/cmd/argocd-dex/commands/argocd_dex.go +++ b/cmd/argocd-dex/commands/argocd_dex.go @@ -8,11 +8,11 @@ import ( "github.com/argoproj/argo-cd/v2/common" - "github.com/ghodss/yaml" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/yaml" cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" "github.com/argoproj/argo-cd/v2/util/cli" diff --git a/cmd/argocd-k8s-auth/commands/argocd_k8s_auth.go b/cmd/argocd-k8s-auth/commands/argocd_k8s_auth.go index 410364e6429df..ce0f3ee3a2f49 100644 --- a/cmd/argocd-k8s-auth/commands/argocd_k8s_auth.go +++ b/cmd/argocd-k8s-auth/commands/argocd_k8s_auth.go @@ -20,6 +20,7 @@ func NewCommand() *cobra.Command { command.AddCommand(newAWSCommand()) command.AddCommand(newGCPCommand()) + command.AddCommand(newAzureCommand()) 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-k8s-auth/commands/azure.go b/cmd/argocd-k8s-auth/commands/azure.go new file mode 100644 index 0000000000000..bc45bbacef48b --- /dev/null +++ b/cmd/argocd-k8s-auth/commands/azure.go @@ -0,0 +1,43 @@ +package commands + +import ( + "os" + + "github.com/Azure/kubelogin/pkg/token" + "github.com/spf13/cobra" + + "github.com/argoproj/argo-cd/v2/util/errors" +) + +var ( + envServerApplicationID = "AAD_SERVER_APPLICATION_ID" + envEnvironmentName = "AAD_ENVIRONMENT_NAME" +) + +const ( + DEFAULT_AAD_SERVER_APPLICATION_ID = "6dae42f8-4368-4678-94ff-3960e28e3630" +) + +func newAzureCommand() *cobra.Command { + o := token.NewOptions() + //we'll use default of WorkloadIdentityLogin for the login flow + o.LoginMethod = token.WorkloadIdentityLogin + o.ServerID = DEFAULT_AAD_SERVER_APPLICATION_ID + var command = &cobra.Command{ + Use: "azure", + Run: func(c *cobra.Command, args []string) { + o.UpdateFromEnv() + if v, ok := os.LookupEnv(envServerApplicationID); ok { + o.ServerID = v + } + if v, ok := os.LookupEnv(envEnvironmentName); ok { + o.Environment = v + } + plugin, err := token.New(&o) + errors.CheckError(err) + err = plugin.Do() + errors.CheckError(err) + }, + } + return command +} diff --git a/cmd/argocd-notification/commands/controller.go b/cmd/argocd-notification/commands/controller.go index d77271f05eab4..cb30fd5277d4b 100644 --- a/cmd/argocd-notification/commands/controller.go +++ b/cmd/argocd-notification/commands/controller.go @@ -43,18 +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 + 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", @@ -74,26 +76,26 @@ func NewCommand() *cobra.Command { restConfig, err := clientConfig.ClientConfig() if err != nil { - return err + return fmt.Errorf("failed to create REST client config: %w", err) } restConfig.UserAgent = fmt.Sprintf("argocd-notifications-controller/%s (%s)", vers.Version, vers.Platform) dynamicClient, err := dynamic.NewForConfig(restConfig) if err != nil { - return err + return fmt.Errorf("failed to create dynamic client: %w", err) } k8sClient, err := kubernetes.NewForConfig(restConfig) if err != nil { - return err + return fmt.Errorf("failed to create Kubernetes client: %w", err) } if namespace == "" { namespace, _, err = clientConfig.Namespace() if err != nil { - return err + return fmt.Errorf("failed to determine controller's host namespace: %w", err) } } level, err := log.ParseLevel(logLevel) if err != nil { - return err + return fmt.Errorf("failed to parse log level: %w", err) } log.SetLevel(level) @@ -105,7 +107,7 @@ func NewCommand() *cobra.Command { log.SetFormatter(&log.TextFormatter{ForceColors: true}) } default: - return fmt.Errorf("Unknown log format '%s'", logFormat) + return fmt.Errorf("unknown log format '%s'", logFormat) } tlsConfig := apiclient.TLSConfiguration{ @@ -118,14 +120,14 @@ func NewCommand() *cobra.Command { fmt.Sprintf("%s/reposerver/tls/ca.crt", env.StringFromEnv(common.EnvAppConfigPath, common.DefaultAppConfigPath)), ) if err != nil { - return err + return fmt.Errorf("failed to load repo-server certificate pool: %w", err) } tlsConfig.Certificates = pool } repoClientset := apiclient.NewRepoServerClientset(argocdRepoServer, 5, tlsConfig) argocdService, err := service.NewArgoCDService(k8sClient, namespace, repoClientset) if err != nil { - return err + return fmt.Errorf("failed to initialize Argo CD service: %w", err) } defer argocdService.Close() @@ -138,10 +140,10 @@ 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, 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 err + return fmt.Errorf("failed to initialize controller: %w", err) } go ctrl.Run(ctx, processorsCount) @@ -153,13 +155,15 @@ func NewCommand() *cobra.Command { command.Flags().IntVar(&processorsCount, "processors-count", 1, "Processors count.") command.Flags().StringVar(&appLabelSelector, "app-label-selector", "", "App label selector.") command.Flags().StringVar(&namespace, "namespace", "", "Namespace which controller handles. Current namespace if empty.") - command.Flags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error") - command.Flags().StringVar(&logFormat, "logformat", "text", "Set the logging format. One of: text|json") + command.Flags().StringVar(&logLevel, "loglevel", env.StringFromEnv("ARGOCD_NOTIFICATIONS_CONTROLLER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error") + command.Flags().StringVar(&logFormat, "logformat", env.StringFromEnv("ARGOCD_NOTIFICATIONS_CONTROLLER_LOGFORMAT", "text"), "Set the logging format. One of: text|json") command.Flags().IntVar(&metricsPort, "metrics-port", defaultMetricsPort, "Metrics port") - command.Flags().StringVar(&argocdRepoServer, "argocd-repo-server", "argocd-repo-server:8081", "Argo CD repo server address") + command.Flags().StringVar(&argocdRepoServer, "argocd-repo-server", common.DefaultRepoServerAddr, "Argo CD repo server address") command.Flags().BoolVar(&argocdRepoServerPlaintext, "argocd-repo-server-plaintext", false, "Use a plaintext client (non-TLS) to connect to repository server") command.Flags().BoolVar(&argocdRepoServerStrictTLS, "argocd-repo-server-strict-tls", false, "Perform strict validation of TLS certificates when connecting to repo server") 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 e5ca1db44ad2e..2ba17cd9b64ba 100644 --- a/cmd/argocd-repo-server/commands/argocd_repo_server.go +++ b/cmd/argocd-repo-server/commands/argocd_repo_server.go @@ -5,11 +5,10 @@ import ( "math" "net" "net/http" - "os" "time" "github.com/argoproj/pkg/stats" - "github.com/go-redis/redis/v8" + "github.com/redis/go-redis/v9" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "google.golang.org/grpc/health/grpc_health_v1" @@ -36,44 +35,28 @@ import ( const ( // CLIName is the name of the CLI - cliName = "argocd-repo-server" - gnuPGSourcePath = "/app/config/gpg/source" - - defaultPauseGenerationAfterFailedGenerationAttempts = 3 - defaultPauseGenerationOnFailureForMinutes = 60 - defaultPauseGenerationOnFailureForRequests = 0 + cliName = "argocd-repo-server" ) -func getGnuPGSourcePath() string { - if path := os.Getenv("ARGOCD_GPG_DATA_PATH"); path != "" { - return path - } else { - return gnuPGSourcePath - } -} - -func getPauseGenerationAfterFailedGenerationAttempts() int { - return env.ParseNumFromEnv(common.EnvPauseGenerationAfterFailedAttempts, defaultPauseGenerationAfterFailedGenerationAttempts, 0, math.MaxInt32) -} - -func getPauseGenerationOnFailureForMinutes() int { - return env.ParseNumFromEnv(common.EnvPauseGenerationMinutes, defaultPauseGenerationOnFailureForMinutes, 0, math.MaxInt32) -} - -func getPauseGenerationOnFailureForRequests() int { - return env.ParseNumFromEnv(common.EnvPauseGenerationRequests, defaultPauseGenerationOnFailureForRequests, 0, math.MaxInt32) -} - -func getSubmoduleEnabled() bool { - return env.ParseBoolFromEnv(common.EnvGitSubmoduleEnabled, true) -} +var ( + gnuPGSourcePath = env.StringFromEnv(common.EnvGPGDataPath, "/app/config/gpg/source") + pauseGenerationAfterFailedGenerationAttempts = env.ParseNumFromEnv(common.EnvPauseGenerationAfterFailedAttempts, 3, 0, math.MaxInt32) + pauseGenerationOnFailureForMinutes = env.ParseNumFromEnv(common.EnvPauseGenerationMinutes, 60, 0, math.MaxInt32) + pauseGenerationOnFailureForRequests = env.ParseNumFromEnv(common.EnvPauseGenerationRequests, 0, 0, math.MaxInt32) + gitSubmoduleEnabled = env.ParseBoolFromEnv(common.EnvGitSubmoduleEnabled, true) +) func NewCommand() *cobra.Command { var ( parallelismLimit int64 listenPort int + listenHost string metricsPort int + metricsHost string otlpAddress string + otlpInsecure bool + otlpHeaders map[string]string + otlpAttrs []string cacheSrc func() (*reposervercache.Cache, error) tlsConfigCustomizer tls.ConfigCustomizer tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error) @@ -84,6 +67,9 @@ func NewCommand() *cobra.Command { allowOutOfBoundsSymlinks bool streamedManifestMaxTarSize string streamedManifestMaxExtractedSize string + helmManifestMaxExtractedSize string + helmRegistryMaxIndexSize string + disableManifestMaxExtractedSize bool ) var command = cobra.Command{ Use: cliName, @@ -122,27 +108,35 @@ func NewCommand() *cobra.Command { streamedManifestMaxExtractedSizeQuantity, err := resource.ParseQuantity(streamedManifestMaxExtractedSize) errors.CheckError(err) + helmManifestMaxExtractedSizeQuantity, err := resource.ParseQuantity(helmManifestMaxExtractedSize) + errors.CheckError(err) + + helmRegistryMaxIndexSizeQuantity, err := resource.ParseQuantity(helmRegistryMaxIndexSize) + errors.CheckError(err) + askPassServer := askpass.NewServer() metricsServer := metrics.NewMetricsServer() cacheutil.CollectMetrics(redisClient, metricsServer) server, err := reposerver.NewServer(metricsServer, cache, tlsConfigCustomizer, repository.RepoServerInitConstants{ ParallelismLimit: parallelismLimit, - PauseGenerationAfterFailedGenerationAttempts: getPauseGenerationAfterFailedGenerationAttempts(), - PauseGenerationOnFailureForMinutes: getPauseGenerationOnFailureForMinutes(), - PauseGenerationOnFailureForRequests: getPauseGenerationOnFailureForRequests(), - SubmoduleEnabled: getSubmoduleEnabled(), + PauseGenerationAfterFailedGenerationAttempts: pauseGenerationAfterFailedGenerationAttempts, + PauseGenerationOnFailureForMinutes: pauseGenerationOnFailureForMinutes, + PauseGenerationOnFailureForRequests: pauseGenerationOnFailureForRequests, + SubmoduleEnabled: gitSubmoduleEnabled, MaxCombinedDirectoryManifestsSize: maxCombinedDirectoryManifestsQuantity, CMPTarExcludedGlobs: cmpTarExcludedGlobs, AllowOutOfBoundsSymlinks: allowOutOfBoundsSymlinks, StreamedManifestMaxExtractedSize: streamedManifestMaxExtractedSizeQuantity.ToDec().Value(), StreamedManifestMaxTarSize: streamedManifestMaxTarSizeQuantity.ToDec().Value(), + HelmManifestMaxExtractedSize: helmManifestMaxExtractedSizeQuantity.ToDec().Value(), + HelmRegistryMaxIndexSize: helmRegistryMaxIndexSizeQuantity.ToDec().Value(), }, askPassServer) errors.CheckError(err) if otlpAddress != "" { var closer func() var err error - closer, err = traceutil.InitTracer(ctx, "argocd-repo-server", otlpAddress) + closer, err = traceutil.InitTracer(ctx, "argocd-repo-server", otlpAddress, otlpInsecure, otlpHeaders, otlpAttrs) if err != nil { log.Fatalf("failed to initialize tracing: %v", err) } @@ -150,7 +144,7 @@ func NewCommand() *cobra.Command { } grpc := server.CreateGRPC() - listener, err := net.Listen("tcp", fmt.Sprintf(":%d", listenPort)) + listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", listenHost, listenPort)) errors.CheckError(err) healthz.ServeHealthCheck(http.DefaultServeMux, func(r *http.Request) error { @@ -176,7 +170,7 @@ func NewCommand() *cobra.Command { return nil }) http.Handle("/metrics", metricsServer.GetHandler()) - go func() { errors.CheckError(http.ListenAndServe(fmt.Sprintf(":%d", metricsPort), nil)) }() + go func() { errors.CheckError(http.ListenAndServe(fmt.Sprintf("%s:%d", metricsHost, metricsPort), nil)) }() go func() { errors.CheckError(askPassServer.Run(askpass.SocketPath)) }() if gpg.IsGPGEnabled() { @@ -184,12 +178,12 @@ func NewCommand() *cobra.Command { err = gpg.InitializeGnuPG() errors.CheckError(err) - log.Infof("Populating GnuPG keyring with keys from %s", getGnuPGSourcePath()) - added, removed, err := gpg.SyncKeyRingFromDirectory(getGnuPGSourcePath()) + log.Infof("Populating GnuPG keyring with keys from %s", gnuPGSourcePath) + added, removed, err := gpg.SyncKeyRingFromDirectory(gnuPGSourcePath) errors.CheckError(err) log.Infof("Loaded %d (and removed %d) keys from keyring", len(added), len(removed)) - go func() { errors.CheckError(reposerver.StartGPGWatcher(getGnuPGSourcePath())) }() + go func() { errors.CheckError(reposerver.StartGPGWatcher(gnuPGSourcePath)) }() } log.Infof("argocd-repo-server is listening on %s", listener.Addr()) @@ -201,24 +195,31 @@ func NewCommand() *cobra.Command { return nil }, } - if cmdutil.LogFormat == "" { - cmdutil.LogFormat = os.Getenv("ARGOCD_REPO_SERVER_LOGLEVEL") - } command.Flags().StringVar(&cmdutil.LogFormat, "logformat", env.StringFromEnv("ARGOCD_REPO_SERVER_LOGFORMAT", "text"), "Set the logging format. One of: text|json") command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", env.StringFromEnv("ARGOCD_REPO_SERVER_LOGLEVEL", "info"), "Set the logging level. One of: debug|info|warn|error") command.Flags().Int64Var(¶llelismLimit, "parallelismlimit", int64(env.ParseNumFromEnv("ARGOCD_REPO_SERVER_PARALLELISM_LIMIT", 0, 0, math.MaxInt32)), "Limit on number of concurrent manifests generate requests. Any value less the 1 means no limit.") + command.Flags().StringVar(&listenHost, "address", env.StringFromEnv("ARGOCD_REPO_SERVER_LISTEN_ADDRESS", common.DefaultAddressRepoServer), "Listen on given address for incoming connections") command.Flags().IntVar(&listenPort, "port", common.DefaultPortRepoServer, "Listen on given port for incoming connections") + 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") command.Flags().StringArrayVar(&cmpTarExcludedGlobs, "plugin-tar-exclude", env.StringsFromEnv("ARGOCD_REPO_SERVER_PLUGIN_TAR_EXCLUSIONS", []string{}, ";"), "Globs to filter when sending tarballs to plugins.") command.Flags().BoolVar(&allowOutOfBoundsSymlinks, "allow-oob-symlinks", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_ALLOW_OUT_OF_BOUNDS_SYMLINKS", false), "Allow out-of-bounds symlinks in repositories (not recommended)") command.Flags().StringVar(&streamedManifestMaxTarSize, "streamed-manifest-max-tar-size", env.StringFromEnv("ARGOCD_REPO_SERVER_STREAMED_MANIFEST_MAX_TAR_SIZE", "100M"), "Maximum size of streamed manifest archives") command.Flags().StringVar(&streamedManifestMaxExtractedSize, "streamed-manifest-max-extracted-size", env.StringFromEnv("ARGOCD_REPO_SERVER_STREAMED_MANIFEST_MAX_EXTRACTED_SIZE", "1G"), "Maximum size of streamed manifest archives when extracted") + 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().StringVar(&helmRegistryMaxIndexSize, "helm-registry-max-index-size", env.StringFromEnv("ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_INDEX_SIZE", "1G"), "Maximum size of registry index file") + 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 df417e71f5e3e..27a2db34189b4 100644 --- a/cmd/argocd-server/commands/argocd_server.go +++ b/cmd/argocd-server/commands/argocd_server.go @@ -4,10 +4,11 @@ import ( "context" "fmt" "math" + "strings" "time" "github.com/argoproj/pkg/stats" - "github.com/go-redis/redis/v8" + "github.com/redis/go-redis/v9" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "k8s.io/client-go/kubernetes" @@ -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" ) @@ -35,23 +39,23 @@ const ( ) var ( - failureRetryCount = 0 - failureRetryPeriodMilliSeconds = 100 + failureRetryCount = env.ParseNumFromEnv(failureRetryCountEnv, 0, 0, 10) + failureRetryPeriodMilliSeconds = env.ParseNumFromEnv(failureRetryPeriodMilliSecondsEnv, 100, 0, 1000) ) -func init() { - failureRetryCount = env.ParseNumFromEnv(failureRetryCountEnv, failureRetryCount, 0, 10) - failureRetryPeriodMilliSeconds = env.ParseNumFromEnv(failureRetryPeriodMilliSecondsEnv, failureRetryPeriodMilliSeconds, 0, 1000) -} - // NewCommand returns a new instance of an argocd command func NewCommand() *cobra.Command { var ( redisClient *redis.Client insecure bool + listenHost string listenPort int + metricsHost string metricsPort int otlpAddress string + otlpInsecure bool + otlpHeaders map[string]string + otlpAttrs []string glogLevel int clientConfig clientcmd.ClientConfig repoServerTimeoutSeconds int @@ -60,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 @@ -104,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) @@ -164,10 +172,17 @@ func NewCommand() *cobra.Command { baseHRef = rootPath } + var contentTypesList []string + if contentTypes != "" { + contentTypesList = strings.Split(contentTypes, ";") + } + argoCDOpts := server.ArgoCDServerOpts{ Insecure: insecure, ListenPort: listenPort, + ListenHost: listenHost, MetricsPort: metricsPort, + MetricsHost: metricsHost, Namespace: namespace, BaseHRef: baseHRef, RootPath: rootPath, @@ -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) + 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,11 +248,17 @@ 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().BoolVar(&enableGZip, "enable-gzip", env.ParseBoolFromEnv("ARGOCD_SERVER_ENABLE_GZIP", false), "Enable GZIP compression") + command.Flags().StringVar(&contentTypes, "api-content-types", env.StringFromEnv("ARGOCD_API_CONTENT_TYPES", "application/json", env.StringFromEnvOpts{AllowEmpty: true}), "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") command.Flags().IntVar(&listenPort, "port", common.DefaultPortAPIServer, "Listen on given port") + 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 \"\".") command.Flags().StringVar(&contentSecurityPolicy, "content-security-policy", env.StringFromEnv("ARGOCD_SERVER_CONTENT_SECURITY_POLICY", "frame-ancestors 'self';"), "Set Content-Security-Policy header in HTTP responses to `value`. To disable, set to \"\".") @@ -239,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/account.go b/cmd/argocd/commands/account.go index 948687efb377e..5472859551f75 100644 --- a/cmd/argocd/commands/account.go +++ b/cmd/argocd/commands/account.go @@ -11,10 +11,10 @@ import ( "time" timeutil "github.com/argoproj/pkg/time" - "github.com/ghodss/yaml" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "golang.org/x/term" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/headless" argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" @@ -26,12 +26,26 @@ import ( "github.com/argoproj/argo-cd/v2/util/io" "github.com/argoproj/argo-cd/v2/util/localconfig" sessionutil "github.com/argoproj/argo-cd/v2/util/session" + "github.com/argoproj/argo-cd/v2/util/templates" ) func NewAccountCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ Use: "account", Short: "Manage account settings", + Example: templates.Examples(` + # List accounts + argocd account list + + # Update the current user's password + argocd account update-password + + # Can I sync any app? + argocd account can-i sync applications '*' + + # Get User information + argocd account get-user-info + `), Run: func(c *cobra.Command, args []string) { c.HelpFunc()(c, args) os.Exit(1) @@ -130,9 +144,9 @@ has appropriate RBAC permissions to change other accounts. }, } - command.Flags().StringVar(¤tPassword, "current-password", "", "password of the currently logged on user") - command.Flags().StringVar(&newPassword, "new-password", "", "new password you want to update to") - command.Flags().StringVar(&account, "account", "", "an account name that should be updated. Defaults to current user account") + command.Flags().StringVar(¤tPassword, "current-password", "", "Password of the currently logged on user") + command.Flags().StringVar(&newPassword, "new-password", "", "New password you want to update to") + command.Flags().StringVar(&account, "account", "", "An account name that should be updated. Defaults to current user account") return command } @@ -143,6 +157,13 @@ func NewAccountGetUserInfoCommand(clientOpts *argocdclient.ClientOptions) *cobra var command = &cobra.Command{ Use: "get-user-info", Short: "Get user info", + Example: templates.Examples(` + # Get User information for the currently logged-in user (see 'argocd login') + argocd account get-user-info + + # Get User information in yaml format + argocd account get-user-info -o yaml + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() diff --git a/cmd/argocd/commands/admin/admin.go b/cmd/argocd/commands/admin/admin.go index 90bbe7e65241e..49c81e4da4bfe 100644 --- a/cmd/argocd/commands/admin/admin.go +++ b/cmd/argocd/commands/admin/admin.go @@ -3,7 +3,6 @@ package admin import ( "reflect" - "github.com/ghodss/yaml" "github.com/spf13/cobra" apiv1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -12,11 +11,15 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/yaml" cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" "github.com/argoproj/argo-cd/v2/common" + argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/settings" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application" ) const ( @@ -27,13 +30,13 @@ const ( var ( configMapResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "configmaps"} secretResource = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "secrets"} - applicationsResource = schema.GroupVersionResource{Group: "argoproj.io", Version: "v1alpha1", Resource: "applications"} - appprojectsResource = schema.GroupVersionResource{Group: "argoproj.io", Version: "v1alpha1", Resource: "appprojects"} - appplicationSetResource = schema.GroupVersionResource{Group: "argoproj.io", Version: "v1alpha1", Resource: "applicationsets"} + applicationsResource = schema.GroupVersionResource{Group: application.Group, Version: "v1alpha1", Resource: application.ApplicationPlural} + appprojectsResource = schema.GroupVersionResource{Group: application.Group, Version: "v1alpha1", Resource: application.AppProjectPlural} + appplicationSetResource = schema.GroupVersionResource{Group: application.Group, Version: "v1alpha1", Resource: application.ApplicationSetPlural} ) // NewAdminCommand returns a new instance of an argocd command -func NewAdminCommand() *cobra.Command { +func NewAdminCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( pathOpts = clientcmd.NewDefaultPathOptions() ) @@ -45,16 +48,97 @@ func NewAdminCommand() *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(pathOpts)) + command.AddCommand(NewClusterCommand(clientOpts, pathOpts)) command.AddCommand(NewProjectsCommand()) command.AddCommand(NewSettingsCommand()) - command.AddCommand(NewAppCommand()) + command.AddCommand(NewAppCommand(clientOpts)) command.AddCommand(NewRepoCommand()) command.AddCommand(NewImportCommand()) command.AddCommand(NewExportCommand()) - command.AddCommand(NewDashboardCommand()) + command.AddCommand(NewDashboardCommand(clientOpts)) command.AddCommand(NewNotificationsCommand()) command.AddCommand(NewInitialPasswordCommand()) @@ -193,11 +277,11 @@ func specsEqual(left, right unstructured.Unstructured) bool { leftData, _, _ := unstructured.NestedMap(left.Object, "data") rightData, _, _ := unstructured.NestedMap(right.Object, "data") return reflect.DeepEqual(leftData, rightData) - case "AppProject": + case application.AppProjectKind: leftSpec, _, _ := unstructured.NestedMap(left.Object, "spec") rightSpec, _, _ := unstructured.NestedMap(right.Object, "spec") return reflect.DeepEqual(leftSpec, rightSpec) - case "Application": + case application.ApplicationKind: leftSpec, _, _ := unstructured.NestedMap(left.Object, "spec") rightSpec, _, _ := unstructured.NestedMap(right.Object, "spec") leftStatus, _, _ := unstructured.NestedMap(left.Object, "status") diff --git a/cmd/argocd/commands/admin/app.go b/cmd/argocd/commands/admin/app.go index e2e2103e75439..ebdec7f261ffc 100644 --- a/cmd/argocd/commands/admin/app.go +++ b/cmd/argocd/commands/admin/app.go @@ -9,7 +9,6 @@ import ( "sort" "time" - "github.com/ghodss/yaml" "github.com/spf13/cobra" apiv1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -18,15 +17,19 @@ import ( "k8s.io/client-go/kubernetes" kubecache "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/yaml" cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" + "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/controller" "github.com/argoproj/argo-cd/v2/controller/cache" "github.com/argoproj/argo-cd/v2/controller/metrics" + "github.com/argoproj/argo-cd/v2/controller/sharding" + argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned" appinformers "github.com/argoproj/argo-cd/v2/pkg/client/informers/externalversions" - argocdclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient" + reposerverclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient" "github.com/argoproj/argo-cd/v2/util/argo" cacheutil "github.com/argoproj/argo-cd/v2/util/cache" appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate" @@ -39,17 +42,27 @@ import ( "github.com/argoproj/argo-cd/v2/util/settings" ) -func NewAppCommand() *cobra.Command { +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) }, } command.AddCommand(NewGenAppSpecCommand()) - command.AddCommand(NewReconcileCommand()) + command.AddCommand(NewReconcileCommand(clientOpts)) command.AddCommand(NewDiffReconcileResults()) return command } @@ -193,14 +206,14 @@ func diffReconcileResults(res1 reconcileResults, res2 reconcileResults) error { for k, v := range resMap1 { firstUn, err := toUnstructured(v) if err != nil { - return err + return fmt.Errorf("error converting first resource to unstructured: %w", err) } var secondUn *unstructured.Unstructured second, ok := resMap2[k] if ok { secondUn, err = toUnstructured(second) if err != nil { - return err + return fmt.Errorf("error converting second resource to unstructured: %w", err) } delete(resMap2, k) } @@ -224,13 +237,14 @@ func diffReconcileResults(res1 reconcileResults, res2 reconcileResults) error { return nil } -func NewReconcileCommand() *cobra.Command { +func NewReconcileCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( clientConfig clientcmd.ClientConfig selector string repoServerAddress string outputFormat string refresh bool + serverSideDiff bool ) var command = &cobra.Command{ @@ -256,18 +270,27 @@ func NewReconcileCommand() *cobra.Command { var result []appReconcileResult if refresh { + appClientset := appclientset.NewForConfigOrDie(cfg) + kubeClientset := kubernetes.NewForConfigOrDie(cfg) if repoServerAddress == "" { printLine("Repo server is not provided, trying to port-forward to argocd-repo-server pod.") overrides := clientcmd.ConfigOverrides{} - repoServerPort, err := kubeutil.PortForward(8081, namespace, &overrides, "app.kubernetes.io/name=argocd-repo-server") + repoServerName := clientOpts.RepoServerName + repoServerServiceLabelSelector := common.LabelKeyComponentRepoServer + "=" + common.LabelValueComponentRepoServer + repoServerServices, err := kubeClientset.CoreV1().Services(namespace).List(context.Background(), v1.ListOptions{LabelSelector: repoServerServiceLabelSelector}) + errors.CheckError(err) + if len(repoServerServices.Items) > 0 { + if repoServerServicelabel, ok := repoServerServices.Items[0].Labels[common.LabelKeyAppName]; ok && repoServerServicelabel != "" { + repoServerName = repoServerServicelabel + } + } + repoServerPodLabelSelector := common.LabelKeyAppName + "=" + repoServerName + repoServerPort, err := kubeutil.PortForward(8081, namespace, &overrides, repoServerPodLabelSelector) errors.CheckError(err) repoServerAddress = fmt.Sprintf("localhost:%d", repoServerPort) } - repoServerClient := argocdclient.NewRepoServerClientset(repoServerAddress, 60, argocdclient.TLSConfiguration{DisableTLS: false, StrictValidation: false}) - - appClientset := appclientset.NewForConfigOrDie(cfg) - kubeClientset := kubernetes.NewForConfigOrDie(cfg) - result, err = reconcileApplications(ctx, kubeClientset, appClientset, namespace, repoServerClient, selector, newLiveStateCache) + repoServerClient := reposerverclient.NewRepoServerClientset(repoServerAddress, 60, reposerverclient.TLSConfiguration{DisableTLS: false, StrictValidation: false}) + result, err = reconcileApplications(ctx, kubeClientset, appClientset, namespace, repoServerClient, selector, newLiveStateCache, serverSideDiff) errors.CheckError(err) } else { appClientset := appclientset.NewForConfigOrDie(cfg) @@ -282,6 +305,7 @@ func NewReconcileCommand() *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 } @@ -328,9 +352,10 @@ func reconcileApplications( kubeClientset kubernetes.Interface, appClientset appclientset.Interface, namespace string, - repoServerClient argocdclient.Clientset, + 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) @@ -371,7 +396,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 { @@ -406,7 +431,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, @@ -418,5 +446,5 @@ func reconcileApplications( } func newLiveStateCache(argoDB db.ArgoDB, appInformer kubecache.SharedIndexInformer, settingsMgr *settings.SettingsManager, server *metrics.MetricsServer) cache.LiveStateCache { - return cache.NewLiveStateCache(argoDB, appInformer, settingsMgr, kubeutil.NewKubectl(), server, func(managedByApp map[string]bool, ref apiv1.ObjectReference) {}, nil, argo.NewResourceTracking()) + return cache.NewLiveStateCache(argoDB, appInformer, settingsMgr, kubeutil.NewKubectl(), server, func(managedByApp map[string]bool, ref apiv1.ObjectReference) {}, &sharding.ClusterSharding{}, argo.NewResourceTracking()) } 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/backup.go b/cmd/argocd/commands/admin/backup.go index 65090ccb9cf71..49e0615c64ba4 100644 --- a/cmd/argocd/commands/admin/backup.go +++ b/cmd/argocd/commands/admin/backup.go @@ -7,7 +7,6 @@ import ( "os" "github.com/argoproj/gitops-engine/pkg/utils/kube" - "github.com/ghodss/yaml" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" apierr "k8s.io/apimachinery/pkg/api/errors" @@ -15,8 +14,10 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/dynamic" "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/common" + "github.com/argoproj/argo-cd/v2/pkg/apis/application" "github.com/argoproj/argo-cd/v2/util/cli" "github.com/argoproj/argo-cd/v2/util/errors" ) @@ -131,7 +132,6 @@ func NewImportCommand() *cobra.Command { errors.CheckError(err) config.QPS = 100 config.Burst = 50 - errors.CheckError(err) namespace, _, err := clientConfig.Namespace() errors.CheckError(err) acdClients := newArgoCDClientsets(config, namespace) @@ -176,12 +176,12 @@ func NewImportCommand() *cobra.Command { applications, err := acdClients.applications.List(ctx, v1.ListOptions{}) errors.CheckError(err) for _, app := range applications.Items { - pruneObjects[kube.ResourceKey{Group: "argoproj.io", Kind: "Application", Name: app.GetName()}] = app + pruneObjects[kube.ResourceKey{Group: application.Group, Kind: application.ApplicationKind, Name: app.GetName()}] = app } projects, err := acdClients.projects.List(ctx, v1.ListOptions{}) errors.CheckError(err) for _, proj := range projects.Items { - pruneObjects[kube.ResourceKey{Group: "argoproj.io", Kind: "AppProject", Name: proj.GetName()}] = proj + pruneObjects[kube.ResourceKey{Group: application.Group, Kind: application.AppProjectKind, Name: proj.GetName()}] = proj } applicationSets, err := acdClients.applicationSets.List(ctx, v1.ListOptions{}) if apierr.IsForbidden(err) || apierr.IsNotFound(err) { @@ -191,7 +191,7 @@ func NewImportCommand() *cobra.Command { } if applicationSets != nil { for _, appSet := range applicationSets.Items { - pruneObjects[kube.ResourceKey{Group: "argoproj.io", Kind: "ApplicationSet", Name: appSet.GetName()}] = appSet + pruneObjects[kube.ResourceKey{Group: application.Group, Kind: application.ApplicationSetKind, Name: appSet.GetName()}] = appSet } } @@ -209,11 +209,11 @@ func NewImportCommand() *cobra.Command { dynClient = acdClients.secrets case "ConfigMap": dynClient = acdClients.configMaps - case "AppProject": + case application.AppProjectKind: dynClient = acdClients.projects - case "Application": + case application.ApplicationKind: dynClient = acdClients.applications - case "ApplicationSet": + case application.ApplicationSetKind: dynClient = acdClients.applicationSets } if !exists { @@ -260,9 +260,9 @@ func NewImportCommand() *cobra.Command { switch key.Kind { case "Secret": dynClient = acdClients.secrets - case "AppProject": + case application.AppProjectKind: dynClient = acdClients.projects - case "Application": + case application.ApplicationKind: dynClient = acdClients.applications if !dryRun { if finalizers := liveObj.GetFinalizers(); len(finalizers) > 0 { @@ -274,7 +274,7 @@ func NewImportCommand() *cobra.Command { } } } - case "ApplicationSet": + case application.ApplicationSetKind: dynClient = acdClients.applicationSets default: log.Fatalf("Unexpected kind '%s' in prune list", key.Kind) @@ -314,7 +314,7 @@ func checkAppHasNoNeedToStopOperation(liveObj unstructured.Unstructured, stopOpe return true } switch liveObj.GetKind() { - case "Application": + case application.ApplicationKind: return liveObj.Object["operation"] == nil } return true @@ -353,9 +353,9 @@ func updateLive(bak, live *unstructured.Unstructured, stopOperation bool) *unstr switch live.GetKind() { case "Secret", "ConfigMap": newLive.Object["data"] = bak.Object["data"] - case "AppProject": + case application.AppProjectKind: newLive.Object["spec"] = bak.Object["spec"] - case "Application": + case application.ApplicationKind: newLive.Object["spec"] = bak.Object["spec"] if _, ok := bak.Object["status"]; ok { newLive.Object["status"] = bak.Object["status"] diff --git a/cmd/argocd/commands/admin/cluster.go b/cmd/argocd/commands/admin/cluster.go index ce59d5401c63b..2e833a68927f4 100644 --- a/cmd/argocd/commands/admin/cluster.go +++ b/cmd/argocd/commands/admin/cluster.go @@ -11,7 +11,7 @@ import ( "time" "github.com/argoproj/gitops-engine/pkg/utils/kube" - "github.com/go-redis/redis/v8" + "github.com/redis/go-redis/v9" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -19,11 +19,13 @@ import ( "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + "k8s.io/utils/pointer" cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/controller/sharding" - argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" + "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" @@ -38,10 +40,19 @@ import ( "github.com/argoproj/argo-cd/v2/util/text/label" ) -func NewClusterCommand(pathOpts *clientcmd.PathOptions) *cobra.Command { +func NewClusterCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clientcmd.PathOptions) *cobra.Command { 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) }, @@ -49,8 +60,8 @@ func NewClusterCommand(pathOpts *clientcmd.PathOptions) *cobra.Command { command.AddCommand(NewClusterConfig()) command.AddCommand(NewGenClusterConfigCommand(pathOpts)) - command.AddCommand(NewClusterStatsCommand()) - command.AddCommand(NewClusterShardsCommand()) + command.AddCommand(NewClusterStatsCommand(clientOpts)) + command.AddCommand(NewClusterShardsCommand(clientOpts)) namespacesCommand := NewClusterNamespacesCommand() namespacesCommand.AddCommand(NewClusterEnableNamespacedMode()) namespacesCommand.AddCommand(NewClusterDisableNamespacedMode()) @@ -60,14 +71,14 @@ func NewClusterCommand(pathOpts *clientcmd.PathOptions) *cobra.Command { } 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) ([]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) @@ -75,16 +86,30 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie if err != nil { return nil, err } + appItems, err := appClient.ArgoprojV1alpha1().Applications(namespace).List(ctx, v1.ListOptions{}) + if err != nil { + return nil, err + } + clusterShardingCache := sharding.NewClusterSharding(argoDB, shard, replicas, shardingAlgorithm) + clusterShardingCache.Init(clustersList, appItems) + clusterShards := clusterShardingCache.GetDistribution() + var cache *appstatecache.Cache if portForwardRedis { overrides := clientcmd.ConfigOverrides{} + redisHaProxyPodLabelSelector := common.LabelKeyAppName + "=" + redisHaProxyName + redisPodLabelSelector := common.LabelKeyAppName + "=" + redisName port, err := kubeutil.PortForward(6379, namespace, &overrides, - "app.kubernetes.io/name=argocd-redis-ha-haproxy", "app.kubernetes.io/name=argocd-redis") + redisHaProxyPodLabelSelector, redisPodLabelSelector) if err != nil { 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 { @@ -92,10 +117,6 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie } } - appItems, err := appClient.ArgoprojV1alpha1().Applications(namespace).List(ctx, v1.ListOptions{}) - if err != nil { - return nil, err - } apps := appItems.Items for i, app := range apps { err := argo.ValidateDestination(ctx, &app.Spec.Destination, argoDB) @@ -105,6 +126,7 @@ 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))) for batchNum := 0; batchNum < batchesCount; batchNum++ { @@ -115,12 +137,13 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie } batch := clustersList.Items[batchStart:batchEnd] _ = kube.RunAllAsync(len(batch), func(i int) error { - cluster := batch[i] clusterShard := 0 + cluster := batch[i] if replicas > 0 { - clusterShard = sharding.GetShardByID(cluster.ID, replicas) + 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 } @@ -142,26 +165,29 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie return clusters, nil } -func getControllerReplicas(ctx context.Context, kubeClient *kubernetes.Clientset, namespace string) (int, error) { +func getControllerReplicas(ctx context.Context, kubeClient *kubernetes.Clientset, namespace string, appControllerName string) (int, error) { + appControllerPodLabelSelector := common.LabelKeyAppName + "=" + appControllerName controllerPods, err := kubeClient.CoreV1().Pods(namespace).List(ctx, v1.ListOptions{ - LabelSelector: "app.kubernetes.io/name=argocd-application-controller"}) + LabelSelector: appControllerPodLabelSelector}) if err != nil { return 0, err } return len(controllerPods.Items), nil } -func NewClusterShardsCommand() *cobra.Command { +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() @@ -175,14 +201,13 @@ func NewClusterShardsCommand() *cobra.Command { appClient := versioned.NewForConfigOrDie(clientCfg) if replicas == 0 { - replicas, err = getControllerReplicas(ctx, kubeClient, namespace) + replicas, err = getControllerReplicas(ctx, kubeClient, namespace, clientOpts.AppControllerName) errors.CheckError(err) } if replicas == 0 { return } - - clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, namespace, portForwardRedis, cacheSrc, shard) + 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 @@ -194,8 +219,16 @@ func NewClusterShardsCommand() *cobra.Command { 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 } @@ -429,17 +462,28 @@ func NewClusterDisableNamespacedMode() *cobra.Command { return &command } -func NewClusterStatsCommand() *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() @@ -453,10 +497,10 @@ func NewClusterStatsCommand() *cobra.Command { kubeClient := kubernetes.NewForConfigOrDie(clientCfg) appClient := versioned.NewForConfigOrDie(clientCfg) if replicas == 0 { - replicas, err = getControllerReplicas(ctx, kubeClient, namespace) + replicas, err = getControllerReplicas(ctx, kubeClient, namespace, clientOpts.AppControllerName) errors.CheckError(err) } - clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, namespace, portForwardRedis, cacheSrc, shard) + 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) @@ -470,8 +514,15 @@ func NewClusterStatsCommand() *cobra.Command { 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 } @@ -484,6 +535,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() @@ -541,6 +604,11 @@ func NewGenClusterConfigCommand(pathOpts *clientcmd.PathOptions) *cobra.Command return } + if clusterOpts.InCluster && clusterOpts.ClusterEndpoint != "" { + log.Fatal("Can only use one of --in-cluster or --cluster-endpoint") + return + } + overrides := clientcmd.ConfigOverrides{ Context: *clstContext, } @@ -549,15 +617,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, @@ -580,8 +649,12 @@ func NewGenClusterConfigCommand(pathOpts *clientcmd.PathOptions) *cobra.Command errors.CheckError(err) clst := cmdutil.NewCluster(contextName, clusterOpts.Namespaces, clusterOpts.ClusterResources, conf, bearerToken, awsAuthConf, execProviderConf, labelsMap, annotationsMap) - if clusterOpts.InCluster { - clst.Server = argoappv1.KubernetesInternalAPIServerAddr + if clusterOpts.InClusterEndpoint() { + 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. + log.Warn("kube-public cluster endpoints are not supported. Falling back to the endpoint listed in the kubconfig context.") } if clusterOpts.Shard >= 0 { clst.Shard = &clusterOpts.Shard diff --git a/cmd/argocd/commands/admin/dashboard.go b/cmd/argocd/commands/admin/dashboard.go index 05a85c47a0a7b..21b621d264022 100644 --- a/cmd/argocd/commands/admin/dashboard.go +++ b/cmd/argocd/commands/admin/dashboard.go @@ -3,19 +3,25 @@ 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" "github.com/argoproj/argo-cd/v2/common" argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" + "github.com/argoproj/argo-cd/v2/util/cache" + "github.com/argoproj/argo-cd/v2/util/env" "github.com/argoproj/argo-cd/v2/util/errors" ) -func NewDashboardCommand() *cobra.Command { +func NewDashboardCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( - port int - address string + port int + address string + compressionStr string + clientConfig clientcmd.ClientConfig ) cmd := &cobra.Command{ Use: "dashboard", @@ -23,13 +29,26 @@ func NewDashboardCommand() *cobra.Command { Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() - errors.CheckError(headless.StartLocalServer(ctx, &argocdclient.ClientOptions{Core: true}, initialize.RetrieveContextIfChanged(cmd.Flag("context")), &port, &address)) + compression, err := cache.CompressionTypeFromString(compressionStr) + errors.CheckError(err) + 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.DefaultAddressAPIServer, "Listen on given address") + 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)") return cmd } diff --git a/cmd/argocd/commands/admin/generatespec_utils.go b/cmd/argocd/commands/admin/generatespec_utils.go index 1a7eb8c99a694..f9d902111a5d1 100644 --- a/cmd/argocd/commands/admin/generatespec_utils.go +++ b/cmd/argocd/commands/admin/generatespec_utils.go @@ -8,8 +8,8 @@ import ( "os" "github.com/argoproj/gitops-engine/pkg/utils/kube" - "github.com/ghodss/yaml" v1 "k8s.io/api/core/v1" + "sigs.k8s.io/yaml" ioutil "github.com/argoproj/argo-cd/v2/util/io" ) diff --git a/cmd/argocd/commands/admin/notifications.go b/cmd/argocd/commands/admin/notifications.go index 990df87391940..3cbac0a53b5c2 100644 --- a/cmd/argocd/commands/admin/notifications.go +++ b/cmd/argocd/commands/admin/notifications.go @@ -15,12 +15,13 @@ import ( settings "github.com/argoproj/argo-cd/v2/util/notification/settings" "github.com/argoproj/argo-cd/v2/util/tls" + "github.com/argoproj/argo-cd/v2/pkg/apis/application" "github.com/argoproj/notifications-engine/pkg/cmd" "github.com/spf13/cobra" ) var ( - applications = schema.GroupVersionResource{Group: "argoproj.io", Version: "v1alpha1", Resource: "applications"} + applications = schema.GroupVersionResource{Group: application.Group, Version: "v1alpha1", Resource: application.ApplicationPlural} ) func NewNotificationsCommand() *cobra.Command { @@ -35,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) @@ -64,7 +65,7 @@ func NewNotificationsCommand() *cobra.Command { log.Fatalf("Failed to initialize Argo CD service: %v", err) } }) - toolsCommand.PersistentFlags().StringVar(&argocdRepoServer, "argocd-repo-server", "argocd-repo-server:8081", "Argo CD repo server address") + toolsCommand.PersistentFlags().StringVar(&argocdRepoServer, "argocd-repo-server", common.DefaultRepoServerAddr, "Argo CD repo server address") toolsCommand.PersistentFlags().BoolVar(&argocdRepoServerPlaintext, "argocd-repo-server-plaintext", false, "Use a plaintext client (non-TLS) to connect to repository server") toolsCommand.PersistentFlags().BoolVar(&argocdRepoServerStrictTLS, "argocd-repo-server-strict-tls", false, "Perform strict validation of TLS certificates when connecting to repo server") return toolsCommand diff --git a/cmd/argocd/commands/admin/project.go b/cmd/argocd/commands/admin/project.go index 1364607cebfa8..8d4d5615bc826 100644 --- a/cmd/argocd/commands/admin/project.go +++ b/cmd/argocd/commands/admin/project.go @@ -14,6 +14,7 @@ import ( "github.com/argoproj/argo-cd/v2/util/cli" "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/io" + "github.com/argoproj/argo-cd/v2/util/templates" "github.com/argoproj/gitops-engine/pkg/utils/kube" "github.com/spf13/cobra" @@ -47,6 +48,17 @@ func NewGenProjectSpecCommand() *cobra.Command { var command = &cobra.Command{ Use: "generate-spec PROJECT", Short: "Generate declarative config for a project", + Example: templates.Examples(` + # Generate a YAML configuration for a project named "myproject" + argocd admin projects generate-spec myproject + + # Generate a JSON configuration for a project named "anotherproject" and specify an output file + argocd admin projects generate-spec anotherproject --output json --file config.json + + # Generate a YAML configuration for a project named "someproject" and write it back to the input file + argocd admin projects generate-spec someproject --inline + `), + Run: func(c *cobra.Command, args []string) { proj, err := cmdutil.ConstructAppProj(fileURL, args, opts, c) errors.CheckError(err) diff --git a/cmd/argocd/commands/admin/project_allowlist.go b/cmd/argocd/commands/admin/project_allowlist.go index 1825a9a1e283f..460ea21d93329 100644 --- a/cmd/argocd/commands/admin/project_allowlist.go +++ b/cmd/argocd/commands/admin/project_allowlist.go @@ -7,7 +7,6 @@ import ( "os" "strings" - "github.com/ghodss/yaml" "github.com/spf13/cobra" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -16,6 +15,7 @@ import ( "k8s.io/client-go/discovery" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/util/errors" @@ -28,6 +28,8 @@ import ( _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" // load the azure plugin (required to authenticate with AKS clusters). _ "k8s.io/client-go/plugin/pkg/client/auth/azure" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application" ) // NewProjectAllowListGenCommand generates a project from clusterRole @@ -39,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) @@ -151,7 +155,7 @@ func generateProjectAllowList(serverResources []*metav1.APIResourceList, cluster } globalProj := v1alpha1.AppProject{ TypeMeta: metav1.TypeMeta{ - Kind: "AppProject", + Kind: application.AppProjectKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{Name: projName}, diff --git a/cmd/argocd/commands/admin/settings.go b/cmd/argocd/commands/admin/settings.go index 9fda66fa73a43..0274b4a422f09 100644 --- a/cmd/argocd/commands/admin/settings.go +++ b/cmd/argocd/commands/admin/settings.go @@ -12,7 +12,6 @@ import ( "text/tabwriter" healthutil "github.com/argoproj/gitops-engine/pkg/health" - "github.com/ghodss/yaml" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" @@ -21,6 +20,7 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" @@ -206,7 +206,7 @@ var validatorsByGroup = map[string]settingValidator{ } ssoProvider = "Dex" } else if general.OIDCConfigRAW != "" { - if _, err := settings.UnmarshalOIDCConfig(general.OIDCConfigRAW); err != nil { + if err := settings.ValidateOIDCConfig(general.OIDCConfigRAW); err != nil { return "", fmt.Errorf("invalid oidc.config: %v", err) } ssoProvider = "OIDC" @@ -233,13 +233,6 @@ var validatorsByGroup = map[string]settingValidator{ _, err := manager.GetGoogleAnalytics() return "", err }), - "plugins": func(manager *settings.SettingsManager) (string, error) { - plugins, err := manager.GetConfigManagementPlugins() - if err != nil { - return "", err - } - return fmt.Sprintf("%d plugins", len(plugins)), nil - }, "kustomize": func(manager *settings.SettingsManager) (string, error) { opts, err := manager.GetKustomizeSettings() if err != nil { @@ -356,6 +349,7 @@ func NewResourceOverridesCommand(cmdCtx commandContext) *cobra.Command { }, } command.AddCommand(NewResourceIgnoreDifferencesCommand(cmdCtx)) + command.AddCommand(NewResourceIgnoreResourceUpdatesCommand(cmdCtx)) command.AddCommand(NewResourceActionListCommand(cmdCtx)) command.AddCommand(NewResourceActionRunCommand(cmdCtx)) command.AddCommand(NewResourceHealthCommand(cmdCtx)) @@ -379,6 +373,27 @@ func executeResourceOverrideCommand(ctx context.Context, cmdCtx commandContext, if gvk.Group != "" { key = fmt.Sprintf("%s/%s", gvk.Group, gvk.Kind) } + override := overrides[key] + callback(res, override, overrides) +} + +func executeIgnoreResourceUpdatesOverrideCommand(ctx context.Context, cmdCtx commandContext, args []string, callback func(res unstructured.Unstructured, override v1alpha1.ResourceOverride, overrides map[string]v1alpha1.ResourceOverride)) { + data, err := os.ReadFile(args[0]) + errors.CheckError(err) + + res := unstructured.Unstructured{} + errors.CheckError(yaml.Unmarshal(data, &res)) + + settingsManager, err := cmdCtx.createSettingsManager(ctx) + errors.CheckError(err) + + overrides, err := settingsManager.GetIgnoreResourceUpdatesOverrides() + errors.CheckError(err) + gvk := res.GroupVersionKind() + key := gvk.Kind + 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) @@ -437,6 +452,52 @@ argocd admin settings resource-overrides ignore-differences ./deploy.yaml --argo return command } +func NewResourceIgnoreResourceUpdatesCommand(cmdCtx commandContext) *cobra.Command { + var command = &cobra.Command{ + Use: "ignore-resource-updates RESOURCE_YAML_PATH", + Short: "Renders fields excluded from resource updates", + Long: "Renders ignored fields using the 'ignoreResourceUpdates' setting specified in the 'resource.customizations' field of 'argocd-cm' ConfigMap", + Example: ` +argocd admin settings resource-overrides ignore-resource-updates ./deploy.yaml --argocd-cm-path ./argocd-cm.yaml`, + Run: func(c *cobra.Command, args []string) { + ctx := c.Context() + + if len(args) < 1 { + c.HelpFunc()(c, args) + os.Exit(1) + } + + executeIgnoreResourceUpdatesOverrideCommand(ctx, cmdCtx, args, func(res unstructured.Unstructured, override v1alpha1.ResourceOverride, overrides map[string]v1alpha1.ResourceOverride) { + gvk := res.GroupVersionKind() + if len(override.IgnoreResourceUpdates.JSONPointers) == 0 && len(override.IgnoreResourceUpdates.JQPathExpressions) == 0 { + _, _ = fmt.Printf("Ignore resource updates are not configured for '%s/%s'\n", gvk.Group, gvk.Kind) + return + } + + normalizer, err := normalizers.NewIgnoreNormalizer(nil, overrides) + errors.CheckError(err) + + normalizedRes := res.DeepCopy() + logs := collectLogs(func() { + errors.CheckError(normalizer.Normalize(normalizedRes)) + }) + if logs != "" { + _, _ = fmt.Println(logs) + } + + if reflect.DeepEqual(&res, normalizedRes) { + _, _ = fmt.Printf("No fields are ignored by ignoreResourceUpdates settings: \n%s\n", override.IgnoreResourceUpdates) + return + } + + _, _ = fmt.Printf("Following fields are ignored:\n\n") + _ = cli.PrintDiff(res.GetName(), &res, normalizedRes) + }) + }, + } + return command +} + func NewResourceHealthCommand(cmdCtx commandContext) *cobra.Command { var command = &cobra.Command{ Use: "health RESOURCE_YAML_PATH", @@ -454,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) + } }) }, } @@ -503,7 +564,7 @@ argocd admin settings resource-overrides action list /tmp/deploy.yaml --argocd-c }) w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) - _, _ = fmt.Fprintf(w, "NAME\tENABLED\n") + _, _ = fmt.Fprintf(w, "NAME\tDISABLED\n") for _, action := range availableActions { _, _ = fmt.Fprintf(w, "%s\t%s\n", action.Name, strconv.FormatBool(action.Disabled)) } @@ -545,13 +606,26 @@ argocd admin settings resource-overrides action run /tmp/deploy.yaml restart --a modifiedRes, err := luaVM.ExecuteResourceAction(&res, action.ActionLua) errors.CheckError(err) - if reflect.DeepEqual(&res, modifiedRes) { - _, _ = fmt.Printf("No fields had been changed by action: \n%s\n", action.Name) - return + for _, impactedResource := range modifiedRes { + result := impactedResource.UnstructuredObj + switch impactedResource.K8SOperation { + // No default case since a not supported operation would have failed upon unmarshaling earlier + case lua.PatchOperation: + if reflect.DeepEqual(&res, modifiedRes) { + _, _ = fmt.Printf("No fields had been changed by action: \n%s\n", action.Name) + return + } + + _, _ = fmt.Printf("Following fields have been changed:\n\n") + _ = cli.PrintDiff(res.GetName(), &res, result) + case lua.CreateOperation: + yamlBytes, err := yaml.Marshal(impactedResource.UnstructuredObj) + errors.CheckError(err) + fmt.Println("Following resource was created:") + fmt.Println(bytes.NewBuffer(yamlBytes).String()) + } } - _, _ = fmt.Printf("Following fields have been changed:\n\n") - _ = cli.PrintDiff(res.GetName(), &res, modifiedRes) }) }, } diff --git a/cmd/argocd/commands/admin/settings_rbac.go b/cmd/argocd/commands/admin/settings_rbac.go index e52887fe33071..1c09fa0d1cfe7 100644 --- a/cmd/argocd/commands/admin/settings_rbac.go +++ b/cmd/argocd/commands/admin/settings_rbac.go @@ -4,14 +4,15 @@ import ( "context" "fmt" "os" + "strings" - "github.com/ghodss/yaml" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/server/rbacpolicy" @@ -22,38 +23,40 @@ import ( // Provide a mapping of short-hand resource names to their RBAC counterparts var resourceMap map[string]string = map[string]string{ - "account": rbacpolicy.ResourceAccounts, - "app": rbacpolicy.ResourceApplications, - "apps": rbacpolicy.ResourceApplications, - "application": rbacpolicy.ResourceApplications, - "cert": rbacpolicy.ResourceCertificates, - "certs": rbacpolicy.ResourceCertificates, - "certificate": rbacpolicy.ResourceCertificates, - "cluster": rbacpolicy.ResourceClusters, - "gpgkey": rbacpolicy.ResourceGPGKeys, - "key": rbacpolicy.ResourceGPGKeys, - "log": rbacpolicy.ResourceLogs, - "logs": rbacpolicy.ResourceLogs, - "exec": rbacpolicy.ResourceExec, - "proj": rbacpolicy.ResourceProjects, - "projs": rbacpolicy.ResourceProjects, - "project": rbacpolicy.ResourceProjects, - "repo": rbacpolicy.ResourceRepositories, - "repos": rbacpolicy.ResourceRepositories, - "repository": rbacpolicy.ResourceRepositories, + "account": rbacpolicy.ResourceAccounts, + "app": rbacpolicy.ResourceApplications, + "apps": rbacpolicy.ResourceApplications, + "application": rbacpolicy.ResourceApplications, + "applicationsets": rbacpolicy.ResourceApplicationSets, + "cert": rbacpolicy.ResourceCertificates, + "certs": rbacpolicy.ResourceCertificates, + "certificate": rbacpolicy.ResourceCertificates, + "cluster": rbacpolicy.ResourceClusters, + "gpgkey": rbacpolicy.ResourceGPGKeys, + "key": rbacpolicy.ResourceGPGKeys, + "log": rbacpolicy.ResourceLogs, + "logs": rbacpolicy.ResourceLogs, + "exec": rbacpolicy.ResourceExec, + "proj": rbacpolicy.ResourceProjects, + "projs": rbacpolicy.ResourceProjects, + "project": rbacpolicy.ResourceProjects, + "repo": rbacpolicy.ResourceRepositories, + "repos": rbacpolicy.ResourceRepositories, + "repository": rbacpolicy.ResourceRepositories, } // List of allowed RBAC resources var validRBACResources map[string]bool = map[string]bool{ - rbacpolicy.ResourceAccounts: true, - rbacpolicy.ResourceApplications: true, - rbacpolicy.ResourceCertificates: true, - rbacpolicy.ResourceClusters: true, - rbacpolicy.ResourceGPGKeys: true, - rbacpolicy.ResourceLogs: true, - rbacpolicy.ResourceExec: true, - rbacpolicy.ResourceProjects: true, - rbacpolicy.ResourceRepositories: true, + rbacpolicy.ResourceAccounts: true, + rbacpolicy.ResourceApplications: true, + rbacpolicy.ResourceApplicationSets: true, + rbacpolicy.ResourceCertificates: true, + rbacpolicy.ResourceClusters: true, + rbacpolicy.ResourceGPGKeys: true, + rbacpolicy.ResourceLogs: true, + rbacpolicy.ResourceExec: true, + rbacpolicy.ResourceProjects: true, + rbacpolicy.ResourceRepositories: true, } // List of allowed RBAC actions @@ -186,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") @@ -199,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") + } + + 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, nil, "") + + userPolicy, _, _ := getPolicy(ctx, policyFile, realClientset, namespace) if userPolicy != "" { if err := rbac.ValidatePolicy(userPolicy); err == nil { fmt.Printf("Policy is valid.\n") @@ -225,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 } @@ -292,11 +329,9 @@ func getPolicyFromConfigMap(cm *corev1.ConfigMap) (string, string, string) { if !ok { userPolicy = "" } - if defaultRole == "" { - defaultRole, ok = cm.Data[rbac.ConfigMapPolicyDefaultKey] - if !ok { - defaultRole = "" - } + defaultRole, ok = cm.Data[rbac.ConfigMapPolicyDefaultKey] + if !ok { + defaultRole = "" } return userPolicy, defaultRole, cm.Data[rbac.ConfigMapMatchModeKey] @@ -373,6 +408,9 @@ func resolveRBACResourceName(name string) string { // isValidRBACAction checks whether a given action is a valid RBAC action func isValidRBACAction(action string) bool { + if strings.HasPrefix(action, rbacpolicy.ActionAction+"/") { + return true + } _, ok := validRBACActions[action] return ok } diff --git a/cmd/argocd/commands/admin/settings_rbac_test.go b/cmd/argocd/commands/admin/settings_rbac_test.go index 93601eed1d303..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) { @@ -27,6 +54,11 @@ func Test_isValidRBACAction(t *testing.T) { }) } +func Test_isValidRBACAction_ActionAction(t *testing.T) { + ok := isValidRBACAction("action/apps/Deployment/restart") + assert.True(t, ok) +} + func Test_isValidRBACResource(t *testing.T) { for k := range validRBACResources { t.Run(k, func(t *testing.T) { @@ -102,6 +134,22 @@ func Test_PolicyFromK8s(t *testing.T) { ok := checkPolicy("role:user", "get", "certificates", ".*", assets.BuiltinPolicyCSV, uPol, "role:readonly", "regex", true) require.False(t, ok) }) + t.Run("get logs", func(t *testing.T) { + ok := checkPolicy("role:test", "get", "logs", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true) + require.True(t, ok) + }) + t.Run("create exec", func(t *testing.T) { + ok := checkPolicy("role:test", "create", "exec", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true) + require.True(t, ok) + }) + t.Run("create applicationsets", func(t *testing.T) { + ok := checkPolicy("role:user", "create", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true) + require.True(t, ok) + }) + t.Run("delete applicationsets", func(t *testing.T) { + ok := checkPolicy("role:user", "delete", "applicationsets", "*/*", assets.BuiltinPolicyCSV, uPol, dRole, "", true) + require.True(t, ok) + }) } func Test_PolicyFromK8sUsingRegex(t *testing.T) { @@ -111,7 +159,12 @@ func Test_PolicyFromK8sUsingRegex(t *testing.T) { p, role:user, clusters, get, .+, allow p, role:user, clusters, get, https://kubernetes.*, deny p, role:user, applications, get, .*, allow -p, role:user, applications, create, .*/.*, allow` +p, role:user, applications, create, .*/.*, allow +p, role:user, applicationsets, create, .*/.*, allow +p, role:user, applicationsets, delete, .*/.*, allow +p, role:user, logs, get, .*/.*, allow +p, role:user, exec, create, .*/.*, allow +` kubeclientset := fake.NewSimpleClientset(&v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -157,4 +210,36 @@ p, role:, certificates, get, .*, allow` ok := checkPolicy("role:user", "get", "certificates", ".+", builtInPolicy, uPol, dRole, "glob", true) require.False(t, ok) }) + t.Run("get logs via glob match mode", func(t *testing.T) { + ok := checkPolicy("role:user", "get", "logs", ".*/.*", builtInPolicy, uPol, dRole, "glob", true) + require.True(t, ok) + }) + t.Run("create exec", func(t *testing.T) { + ok := checkPolicy("role:user", "create", "exec", ".*/.*", builtInPolicy, uPol, dRole, "regex", true) + require.True(t, ok) + }) + t.Run("create applicationsets", func(t *testing.T) { + ok := checkPolicy("role:user", "create", "applicationsets", ".*/.*", builtInPolicy, uPol, dRole, "regex", true) + require.True(t, ok) + }) + t.Run("delete applicationsets", func(t *testing.T) { + ok := checkPolicy("role:user", "delete", "applicationsets", ".*/.*", builtInPolicy, uPol, dRole, "regex", true) + 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 696387d0e01fc..ff817017f4be5 100644 --- a/cmd/argocd/commands/admin/settings_test.go +++ b/cmd/argocd/commands/admin/settings_test.go @@ -151,13 +151,6 @@ clientSecret: aaaabbbbccccddddeee`, }, containsSummary: "Dex is configured ('url' field is missing)", }, - "Plugins_ValidConfig": { - validator: "plugins", - data: map[string]string{ - "configManagementPlugins": `[{"name": "test1"}, {"name": "test2"}]`, - }, - containsSummary: "2 plugins", - }, "Kustomize_ModifiedOptions": { validator: "kustomize", containsSummary: "default options", @@ -233,6 +226,29 @@ 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 +metadata: + name: hello + namespace: test-ns + uid: "123" +spec: + schedule: "* * * * *"` +) + func tempFile(content string) (string, io.Closer, error) { f, err := os.CreateTemp("", "*.yaml") if err != nil { @@ -281,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) { @@ -301,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 } @@ -309,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" } `})) @@ -342,6 +373,12 @@ func TestResourceOverrideAction(t *testing.T) { } defer utils.Close(closer) + cronJobFile, closer, err := tempFile(testCronJobYAML) + if !assert.NoError(t, err) { + return + } + defer utils.Close(closer) + t.Run("NoActions", func(t *testing.T) { cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{ "resource.customizations": `apps/Deployment: {}`})) @@ -354,7 +391,7 @@ func TestResourceOverrideAction(t *testing.T) { assert.Contains(t, out, "Actions are not configured") }) - t.Run("ActionConfigured", func(t *testing.T) { + t.Run("OldStyleActionConfigured", func(t *testing.T) { cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{ "resource.customizations": `apps/Deployment: actions: | @@ -383,9 +420,55 @@ func TestResourceOverrideAction(t *testing.T) { assert.NoError(t, err) }) assert.NoError(t, err) - assert.Contains(t, out, `NAME ENABLED + assert.Contains(t, out, `NAME DISABLED restart false resume false `) }) + + t.Run("NewStyleActionConfigured", func(t *testing.T) { + cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{ + "resource.customizations": `batch/CronJob: + actions: | + discovery.lua: | + actions = {} + actions["create-a-job"] = {["disabled"] = false} + return actions + definitions: + - name: test + action.lua: | + job1 = {} + job1.apiVersion = "batch/v1" + job1.kind = "Job" + job1.metadata = {} + job1.metadata.name = "hello-1" + job1.metadata.namespace = "obj.metadata.namespace" + impactedResource1 = {} + impactedResource1.operation = "create" + impactedResource1.resource = job1 + result = {} + result[1] = impactedResource1 + return result +`})) + out, err := captureStdout(func() { + cmd.SetArgs([]string{"run-action", cronJobFile, "test"}) + err := cmd.Execute() + assert.NoError(t, err) + }) + assert.NoError(t, err) + assert.Contains(t, out, "resource was created:") + assert.Contains(t, out, "hello-1") + + out, err = captureStdout(func() { + cmd.SetArgs([]string{"list-actions", cronJobFile}) + err := cmd.Execute() + assert.NoError(t, err) + }) + + assert.NoError(t, err) + assert.Contains(t, out, "NAME") + assert.Contains(t, out, "DISABLED") + assert.Contains(t, out, "create-a-job") + assert.Contains(t, out, "false") + }) } diff --git a/cmd/argocd/commands/admin/testdata/rbac/argocd-rbac-cm.yaml b/cmd/argocd/commands/admin/testdata/rbac/argocd-rbac-cm.yaml index 06cb30e8df665..bf947fb8b7110 100644 --- a/cmd/argocd/commands/admin/testdata/rbac/argocd-rbac-cm.yaml +++ b/cmd/argocd/commands/admin/testdata/rbac/argocd-rbac-cm.yaml @@ -8,6 +8,8 @@ data: p, role:user, applications, create, */*, allow p, role:user, applications, delete, *, allow p, role:user, applications, delete, */guestbook, deny + p, role:user, applicationsets, create, */*, allow + p, role:user, applicationsets, delete, */*, allow p, role:user, logs, get, */*, allow g, test, role:user policy.default: role:unknown diff --git a/cmd/argocd/commands/admin/testdata/rbac/policy.csv b/cmd/argocd/commands/admin/testdata/rbac/policy.csv index a92060ec3b4fe..b18d0904f5f60 100644 --- a/cmd/argocd/commands/admin/testdata/rbac/policy.csv +++ b/cmd/argocd/commands/admin/testdata/rbac/policy.csv @@ -5,6 +5,8 @@ p, role:user, applications, get, *, allow p, role:user, applications, create, */*, allow p, role:user, applications, delete, *, allow p, role:user, applications, delete, */guestbook, deny +p, role:user, applicationsets, create, */*, allow +p, role:user, applicationsets, delete, */*, allow p, role:test, certificates, get, *, allow p, role:test, logs, get, */*, allow p, role:test, exec, create, */*, allow diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go index b2a4c6f13933b..3c0f1e7ad672b 100644 --- a/cmd/argocd/commands/app.go +++ b/cmd/argocd/commands/app.go @@ -19,7 +19,6 @@ import ( "github.com/argoproj/gitops-engine/pkg/sync/hook" "github.com/argoproj/gitops-engine/pkg/sync/ignore" "github.com/argoproj/gitops-engine/pkg/utils/kube" - "github.com/ghodss/yaml" grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry" "github.com/mattn/go-isatty" log "github.com/sirupsen/logrus" @@ -29,19 +28,18 @@ import ( "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" + k8swatch "k8s.io/apimachinery/pkg/watch" "k8s.io/utils/pointer" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/headless" cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" - argocommon "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/controller" argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" - applicationpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" clusterpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster" projectpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/project" "github.com/argoproj/argo-cd/v2/pkg/apiclient/settings" - settingspkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/settings" argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" repoapiclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient" "github.com/argoproj/argo-cd/v2/reposerver/repository" @@ -53,6 +51,7 @@ import ( "github.com/argoproj/argo-cd/v2/util/grpc" argoio "github.com/argoproj/argo-cd/v2/util/io" "github.com/argoproj/argo-cd/v2/util/manifeststream" + "github.com/argoproj/argo-cd/v2/util/templates" "github.com/argoproj/argo-cd/v2/util/text/label" ) @@ -94,6 +93,8 @@ func NewApplicationCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comman command.AddCommand(NewApplicationResourceActionsCommand(clientOpts)) command.AddCommand(NewApplicationListResourcesCommand(clientOpts)) command.AddCommand(NewApplicationLogsCommand(clientOpts)) + command.AddCommand(NewApplicationAddSourceCommand(clientOpts)) + command.AddCommand(NewApplicationRemoveSourceCommand(clientOpts)) return command } @@ -103,6 +104,7 @@ type watchOpts struct { operation bool suspended bool degraded bool + delete bool } // NewApplicationCreateCommand returns a new instance of an `argocd app create` command @@ -135,13 +137,15 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra. # Create a Kustomize app argocd app create kustomize-guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path kustomize-guestbook --dest-namespace default --dest-server https://kubernetes.default.svc --kustomize-image gcr.io/heptio-images/ks-guestbook-demo:0.1 + # Create a MultiSource app while yaml file contains an application with multiple sources + argocd app create guestbook --file + # Create a app using a custom tool: argocd app create kasane --repo https://github.com/argoproj/argocd-example-apps.git --path plugins/kasane --dest-namespace default --dest-server https://kubernetes.default.svc --config-management-plugin kasane`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() argocdClient := headless.NewClientOrDie(clientOpts, c) - apps, err := cmdutil.ConstructApps(fileURL, appName, labels, annotations, args, appOpts, c.Flags()) errors.CheckError(err) @@ -150,9 +154,6 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra. c.HelpFunc()(c, args) os.Exit(1) } - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning) - } if appNamespace != "" { app.Namespace = appNamespace } @@ -161,15 +162,17 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra. } conn, appIf := argocdClient.NewApplicationClientOrDie() defer argoio.Close(conn) - appCreateRequest := applicationpkg.ApplicationCreateRequest{ + appCreateRequest := application.ApplicationCreateRequest{ Application: app, Upsert: &upsert, Validate: &appOpts.Validate, } // Get app before creating to see if it is being updated or no change - existing, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &app.Name}) - if grpc.UnwrapGRPCStatus(err).Code() != codes.NotFound { + existing, err := appIf.Get(ctx, &application.ApplicationQuery{Name: &app.Name}) + unwrappedError := grpc.UnwrapGRPCStatus(err).Code() + // As part of the fix for CVE-2022-41354, the API will return Permission Denied when an app does not exist. + if unwrappedError != codes.NotFound && unwrappedError != codes.PermissionDenied { errors.CheckError(err) } @@ -263,6 +266,52 @@ func hasAppChanged(appReq, appRes *argoappv1.Application, upsert bool) bool { return true } +func parentChildDetails(appIf application.ApplicationServiceClient, ctx context.Context, appName string, appNs string) (map[string]argoappv1.ResourceNode, map[string][]string, map[string]struct{}) { + + mapUidToNode := make(map[string]argoappv1.ResourceNode) + mapParentToChild := make(map[string][]string) + parentNode := make(map[string]struct{}) + + resourceTree, err := appIf.ResourceTree(ctx, &application.ResourcesQuery{Name: &appName, AppNamespace: &appNs, ApplicationName: &appName}) + errors.CheckError(err) + + for _, node := range resourceTree.Nodes { + mapUidToNode[node.UID] = node + + if len(node.ParentRefs) > 0 { + _, ok := mapParentToChild[node.ParentRefs[0].UID] + if !ok { + var temp []string + mapParentToChild[node.ParentRefs[0].UID] = temp + } + mapParentToChild[node.ParentRefs[0].UID] = append(mapParentToChild[node.ParentRefs[0].UID], node.UID) + } else { + parentNode[node.UID] = struct{}{} + } + } + return mapUidToNode, mapParentToChild, parentNode +} + +func printHeader(acdClient argocdclient.Client, app *argoappv1.Application, ctx context.Context, windows *argoappv1.SyncWindows, showOperation bool, showParams bool) { + aURL := appURL(ctx, acdClient, app.Name) + printAppSummaryTable(app, aURL, windows) + + if len(app.Status.Conditions) > 0 { + fmt.Println() + w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) + printAppConditions(w, app) + _ = w.Flush() + fmt.Println() + } + if showOperation && app.Status.OperationState != nil { + fmt.Println() + printOperationResult(app.Status.OperationState) + } + if !app.Spec.HasMultipleSources() && showParams { + printParams(app) + } +} + // NewApplicationGetCommand returns a new instance of an `argocd app get` command func NewApplicationGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( @@ -271,13 +320,42 @@ func NewApplicationGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com output string showParams bool showOperation bool + appNamespace string ) 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 { c.HelpFunc()(c, args) os.Exit(1) @@ -286,17 +364,15 @@ func NewApplicationGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com conn, appIf := acdClient.NewApplicationClientOrDie() defer argoio.Close(conn) - appName, appNs := argo.ParseAppQualifiedName(args[0], "") - app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{ + appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) + + app, err := appIf.Get(ctx, &application.ApplicationQuery{ Name: &appName, Refresh: getRefreshType(refresh, hardRefresh), AppNamespace: &appNs, }) - errors.CheckError(err) - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning) - } + errors.CheckError(err) pConn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() defer argoio.Close(pConn) @@ -310,39 +386,38 @@ func NewApplicationGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com err := PrintResource(app, output) errors.CheckError(err) case "wide", "": - aURL := appURL(ctx, acdClient, app.Name) - printAppSummaryTable(app, aURL, windows) - - if len(app.Status.Conditions) > 0 { + printHeader(acdClient, app, ctx, windows, showOperation, showParams) + if len(app.Status.Resources) > 0 { fmt.Println() w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) - printAppConditions(w, app) + printAppResources(w, app) _ = w.Flush() - fmt.Println() } - if showOperation && app.Status.OperationState != nil { + case "tree": + printHeader(acdClient, app, ctx, windows, showOperation, showParams) + mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs) + if len(mapUidToNode) > 0 { fmt.Println() - printOperationResult(app.Status.OperationState) - } - if showParams { - printParams(app) + printTreeView(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState) } - if len(app.Status.Resources) > 0 { + case "tree=detailed": + printHeader(acdClient, app, ctx, windows, showOperation, showParams) + mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs) + if len(mapUidToNode) > 0 { fmt.Println() - w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) - printAppResources(w, app) - _ = w.Flush() + printTreeViewDetailed(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState) } default: errors.CheckError(fmt.Errorf("unknown output format: %s", output)) } }, } - command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide") + command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|tree") command.Flags().BoolVar(&showOperation, "show-operation", false, "Show application operation") command.Flags().BoolVar(&showParams, "show-params", false, "Show application parameters and overrides") command.Flags().BoolVar(&refresh, "refresh", false, "Refresh application data when retrieving") command.Flags().BoolVar(&hardRefresh, "hard-refresh", false, "Refresh application data as well as target manifests cache") + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Only get application from namespace") return command } @@ -364,6 +439,44 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co var command = &cobra.Command{ Use: "logs APPNAME", Short: "Get logs of application pods", + Example: templates.Examples(` + # Get logs of pods associated with the application "my-app" + argocd app logs my-app + + # Get logs of pods associated with the application "my-app" in a specific resource group + argocd app logs my-app --group my-group + + # Get logs of pods associated with the application "my-app" in a specific resource kind + argocd app logs my-app --kind my-kind + + # Get logs of pods associated with the application "my-app" in a specific namespace + argocd app logs my-app --namespace my-namespace + + # Get logs of pods associated with the application "my-app" for a specific resource name + argocd app logs my-app --name my-resource + + # Stream logs in real-time for the application "my-app" + argocd app logs my-app -f + + # Get the last N lines of logs for the application "my-app" + argocd app logs my-app --tail 100 + + # Get logs since a specified number of seconds ago + argocd app logs my-app --since-seconds 3600 + + # Get logs until a specified time (format: "2023-10-10T15:30:00Z") + argocd app logs my-app --until-time "2023-10-10T15:30:00Z" + + # Filter logs to show only those containing a specific string + argocd app logs my-app --filter "error" + + # Get logs for a specific container within the pods + argocd app logs my-app -c my-container + + # Get previously terminated container logs + argocd app logs my-app -p + `), + Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -374,12 +487,12 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co acdClient := headless.NewClientOrDie(clientOpts, c) conn, appIf := acdClient.NewApplicationClientOrDie() defer argoio.Close(conn) - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + appName, appNs := argo.ParseFromQualifiedName(args[0], "") retry := true for retry { retry = false - stream, err := appIf.PodLogs(ctx, &applicationpkg.ApplicationPodLogsQuery{ + stream, err := appIf.PodLogs(ctx, &application.ApplicationPodLogsQuery{ Name: &appName, Group: &group, Namespace: pointer.String(namespace), @@ -419,8 +532,8 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co } else { return } - } //Done with receive message - } //Done with retry + } // Done with receive message + } // Done with retry }, } @@ -428,28 +541,31 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co command.Flags().StringVar(&kind, "kind", "", "Resource kind") command.Flags().StringVar(&namespace, "namespace", "", "Resource namespace") command.Flags().StringVar(&resourceName, "name", "", "Resource name") - command.Flags().BoolVar(&follow, "follow", false, "Specify if the logs should be streamed") + command.Flags().BoolVarP(&follow, "follow", "f", false, "Specify if the logs should be streamed") command.Flags().Int64Var(&tail, "tail", 0, "The number of lines from the end of the logs to show") command.Flags().Int64Var(&sinceSeconds, "since-seconds", 0, "A relative time in seconds before the current time from which to show logs") command.Flags().StringVar(&untilTime, "until-time", "", "Show logs until this time") command.Flags().StringVar(&filter, "filter", "", "Show logs contain this string") - command.Flags().StringVar(&container, "container", "", "Optional container name") + command.Flags().StringVarP(&container, "container", "c", "", "Optional container name") command.Flags().BoolVarP(&previous, "previous", "p", false, "Specify if the previously terminated container logs should be returned") return command } func printAppSummaryTable(app *argoappv1.Application, appURL string, windows *argoappv1.SyncWindows) { - source := app.Spec.GetSource() fmt.Printf(printOpFmtStr, "Name:", app.QualifiedName()) fmt.Printf(printOpFmtStr, "Project:", app.Spec.GetProject()) fmt.Printf(printOpFmtStr, "Server:", getServer(app)) fmt.Printf(printOpFmtStr, "Namespace:", app.Spec.Destination.Namespace) fmt.Printf(printOpFmtStr, "URL:", appURL) - fmt.Printf(printOpFmtStr, "Repo:", source.RepoURL) - fmt.Printf(printOpFmtStr, "Target:", source.TargetRevision) - fmt.Printf(printOpFmtStr, "Path:", source.Path) - printAppSourceDetails(&source) + if !app.Spec.HasMultipleSources() { + fmt.Println("Source:") + } else { + fmt.Println("Sources:") + } + for _, source := range app.Spec.GetSources() { + printAppSourceDetails(&source) + } var wds []string var status string var allow, deny, inactiveAllows bool @@ -497,7 +613,7 @@ func printAppSummaryTable(app *argoappv1.Application, appURL string, windows *ar syncPolicy += " (Prune)" } } else { - syncPolicy = "" + syncPolicy = "Manual" } fmt.Printf(printOpFmtStr, "Sync Policy:", syncPolicy) syncStatusStr := string(app.Status.Sync.Status) @@ -519,11 +635,19 @@ func printAppSummaryTable(app *argoappv1.Application, appURL string, windows *ar } func printAppSourceDetails(appSrc *argoappv1.ApplicationSource) { + fmt.Printf(printOpFmtStr, "- Repo:", appSrc.RepoURL) + fmt.Printf(printOpFmtStr, " Target:", appSrc.TargetRevision) + if appSrc.Path != "" { + fmt.Printf(printOpFmtStr, " Path:", appSrc.Path) + } + if appSrc.Ref != "" { + fmt.Printf(printOpFmtStr, " Ref:", appSrc.Ref) + } if appSrc.Helm != nil && len(appSrc.Helm.ValueFiles) > 0 { - fmt.Printf(printOpFmtStr, "Helm Values:", strings.Join(appSrc.Helm.ValueFiles, ",")) + fmt.Printf(printOpFmtStr, " Helm Values:", strings.Join(appSrc.Helm.ValueFiles, ",")) } if appSrc.Kustomize != nil && appSrc.Kustomize.NamePrefix != "" { - fmt.Printf(printOpFmtStr, "Name Prefix:", appSrc.Kustomize.NamePrefix) + fmt.Printf(printOpFmtStr, " Name Prefix:", appSrc.Kustomize.NamePrefix) } } @@ -554,7 +678,7 @@ func appURLDefault(acdClient argocdclient.Client, appName string) string { func appURL(ctx context.Context, acdClient argocdclient.Client, appName string) string { conn, settingsIf := acdClient.NewSettingsClientOrDie() defer argoio.Close(conn) - argoSettings, err := settingsIf.Get(ctx, &settingspkg.SettingsQuery{}) + argoSettings, err := settingsIf.Get(ctx, &settings.SettingsQuery{}) errors.CheckError(err) if argoSettings.URL != "" { @@ -606,11 +730,33 @@ func getServer(app *argoappv1.Application) string { // NewApplicationSetCommand returns a new instance of an `argocd app set` command func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( - appOpts cmdutil.AppOptions + appOpts cmdutil.AppOptions + appNamespace string + sourceIndex int ) var command = &cobra.Command{ Use: "set APPNAME", Short: "Set application parameters", + Example: templates.Examples(` + # Set application parameters for the application "my-app" + argocd app set my-app --parameter key1=value1 --parameter key2=value2 + + # Set and validate application parameters for "my-app" + argocd app set my-app --parameter key1=value1 --parameter key2=value2 --validate + + # Set and override application parameters with JSON or YAML file + argocd app set my-app --from-file path/to/parameters.json + + # Set and override application parameters with a parameter file + argocd app set my-app --parameter-file path/to/parameter-file.yaml + + # Set and override application parameters for a source at index 1 under spec.sources of app my-app. source-index starts at 1. + argocd app set my-app --source-index 1 --repo https://github.com/argoproj/argocd-example-apps.git + + # Set application parameters and specify the namespace + argocd app set my-app --parameter key1=value1 --parameter key2=value2 --namespace my-namespace + `), + Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -618,26 +764,33 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com c.HelpFunc()(c, args) os.Exit(1) } - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) argocdClient := headless.NewClientOrDie(clientOpts, c) conn, appIf := argocdClient.NewApplicationClientOrDie() defer argoio.Close(conn) - app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName, AppNamespace: &appNs}) + app, err := appIf.Get(ctx, &application.ApplicationQuery{Name: &appName, AppNamespace: &appNs}) errors.CheckError(err) - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning) + if app.Spec.HasMultipleSources() { + if sourceIndex <= 0 { + errors.CheckError(fmt.Errorf("Source index should be specified and greater than 0 for applications with multiple sources")) + } + if len(app.Spec.GetSources()) < sourceIndex { + errors.CheckError(fmt.Errorf("Source index should be less than the number of sources in the application")) + } } - visited := cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts) + // sourceIndex startes with 1, thus, it needs to be decreased by 1 to find the correct index in the list of sources + sourceIndex = sourceIndex - 1 + visited := cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts, sourceIndex) if visited == 0 { log.Error("Please set at least one option to update") c.HelpFunc()(c, args) os.Exit(1) } - setParameterOverrides(app, appOpts.Parameters) - _, err = appIf.UpdateSpec(ctx, &applicationpkg.ApplicationUpdateSpecRequest{ + setParameterOverrides(app, appOpts.Parameters, sourceIndex) + _, err = appIf.UpdateSpec(ctx, &application.ApplicationUpdateSpecRequest{ Name: &app.Name, Spec: &app.Spec, Validate: &appOpts.Validate, @@ -646,7 +799,9 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com errors.CheckError(err) }, } + command.Flags().IntVar(&sourceIndex, "source-index", -1, "Index of the source from the list of sources of the app. Index starts at 1.") cmdutil.AddAppFlags(command, &appOpts) + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Set application parameters in namespace") return command } @@ -655,28 +810,49 @@ type unsetOpts struct { namePrefix bool nameSuffix bool kustomizeVersion bool + kustomizeNamespace bool kustomizeImages []string + kustomizeReplicas []string parameters []string valuesFiles []string valuesLiteral bool ignoreMissingValueFiles bool pluginEnvs []string passCredentials bool + ref bool +} + +// IsZero returns true when the Application options for kustomize are considered empty +func (o *unsetOpts) KustomizeIsZero() bool { + return o == nil || + !o.namePrefix && + !o.nameSuffix && + !o.kustomizeVersion && + !o.kustomizeNamespace && + len(o.kustomizeImages) == 0 && + len(o.kustomizeReplicas) == 0 } // NewApplicationUnsetCommand returns a new instance of an `argocd app unset` command func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var ( + sourceIndex int + ) appOpts := cmdutil.AppOptions{} opts := unsetOpts{} + var appNamespace string var command = &cobra.Command{ Use: "unset APPNAME parameters", Short: "Unset application parameters", Example: ` # Unset kustomize override kustomize image argocd app unset my-app --kustomize-image=alpine - # Unset kustomize override prefix + # Unset kustomize override suffix argocd app unset my-app --namesuffix + # Unset kustomize override suffix for source at index 1 under spec.sources of app my-app. source-index starts at 1. + argocd app unset my-app --source-index 1 --namesuffix + # Unset parameter override argocd app unset my-app -p COMPONENT=PARAM`, @@ -687,18 +863,25 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C c.HelpFunc()(c, args) os.Exit(1) } - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + + appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() defer argoio.Close(conn) - app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName, AppNamespace: &appNs}) + app, err := appIf.Get(ctx, &application.ApplicationQuery{Name: &appName, AppNamespace: &appNs}) errors.CheckError(err) - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning) + if app.Spec.HasMultipleSources() { + if sourceIndex <= 0 { + errors.CheckError(fmt.Errorf("Source index should be specified and greater than 0 for applications with multiple sources")) + } + if len(app.Spec.GetSources()) < sourceIndex { + errors.CheckError(fmt.Errorf("Source index should be less than the number of sources in the application")) + } } - source := app.Spec.GetSource() - updated, nothingToUnset := unset(&source, opts) + source := app.Spec.GetSourcePtr(sourceIndex) + + updated, nothingToUnset := unset(source, opts) if nothingToUnset { c.HelpFunc()(c, args) os.Exit(1) @@ -707,8 +890,8 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C return } - cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts) - _, err = appIf.UpdateSpec(ctx, &applicationpkg.ApplicationUpdateSpecRequest{ + cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts, sourceIndex) + _, err = appIf.UpdateSpec(ctx, &application.ApplicationUpdateSpecRequest{ Name: &app.Name, Spec: &app.Spec, Validate: &appOpts.Validate, @@ -717,6 +900,7 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C errors.CheckError(err) }, } + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Unset application parameters in namespace") command.Flags().StringArrayVarP(&opts.parameters, "parameter", "p", []string{}, "Unset a parameter override (e.g. -p guestbook=image)") command.Flags().StringArrayVar(&opts.valuesFiles, "values", []string{}, "Unset one or more Helm values files") command.Flags().BoolVar(&opts.valuesLiteral, "values-literal", false, "Unset literal Helm values block") @@ -724,16 +908,27 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C command.Flags().BoolVar(&opts.nameSuffix, "namesuffix", false, "Kustomize namesuffix") command.Flags().BoolVar(&opts.namePrefix, "nameprefix", false, "Kustomize nameprefix") command.Flags().BoolVar(&opts.kustomizeVersion, "kustomize-version", false, "Kustomize version") + command.Flags().BoolVar(&opts.kustomizeNamespace, "kustomize-namespace", false, "Kustomize namespace") command.Flags().StringArrayVar(&opts.kustomizeImages, "kustomize-image", []string{}, "Kustomize images name (e.g. --kustomize-image node --kustomize-image mysql)") + command.Flags().StringArrayVar(&opts.kustomizeReplicas, "kustomize-replica", []string{}, "Kustomize replicas name (e.g. --kustomize-replica my-deployment --kustomize-replica my-statefulset)") command.Flags().StringArrayVar(&opts.pluginEnvs, "plugin-env", []string{}, "Unset plugin env variables (e.g --plugin-env name)") command.Flags().BoolVar(&opts.passCredentials, "pass-credentials", false, "Unset passCredentials") + command.Flags().BoolVar(&opts.ref, "ref", false, "Unset ref on the source") + command.Flags().IntVar(&sourceIndex, "source-index", -1, "Index of the source from the list of sources of the app. Index starts at 1.") return command } func unset(source *argoappv1.ApplicationSource, opts unsetOpts) (updated bool, nothingToUnset bool) { + needToUnsetRef := false + if opts.ref && source.Ref != "" { + source.Ref = "" + updated = true + needToUnsetRef = true + } + if source.Kustomize != nil { - if !opts.namePrefix && !opts.nameSuffix && !opts.kustomizeVersion && len(opts.kustomizeImages) == 0 { - return false, true + if opts.KustomizeIsZero() { + return updated, !needToUnsetRef } if opts.namePrefix && source.Kustomize.NamePrefix != "" { @@ -751,11 +946,16 @@ func unset(source *argoappv1.ApplicationSource, opts unsetOpts) (updated bool, n source.Kustomize.Version = "" } + if opts.kustomizeNamespace && source.Kustomize.Namespace != "" { + updated = true + source.Kustomize.Namespace = "" + } + for _, kustomizeImage := range opts.kustomizeImages { 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). @@ -764,10 +964,21 @@ func unset(source *argoappv1.ApplicationSource, opts unsetOpts) (updated bool, n } } } + + for _, kustomizeReplica := range opts.kustomizeReplicas { + kustomizeReplicas := source.Kustomize.Replicas + for i, item := range kustomizeReplicas { + if kustomizeReplica == item.Name { + source.Kustomize.Replicas = append(kustomizeReplicas[0:i], kustomizeReplicas[i+1:]...) + updated = true + break + } + } + } } if source.Helm != nil { if len(opts.parameters) == 0 && len(opts.valuesFiles) == 0 && !opts.valuesLiteral && !opts.ignoreMissingValueFiles && !opts.passCredentials { - return false, true + return updated, !needToUnsetRef } for _, paramStr := range opts.parameters { helmParams := source.Helm.Parameters @@ -779,9 +990,11 @@ func unset(source *argoappv1.ApplicationSource, opts unsetOpts) (updated bool, n } } } - if opts.valuesLiteral && source.Helm.Values != "" { - source.Helm.Values = "" - updated = true + if opts.valuesLiteral && !source.Helm.ValuesIsEmpty() { + err := source.Helm.SetValuesString("") + if err == nil { + updated = true + } } for _, valuesFile := range opts.valuesFiles { specValueFiles := source.Helm.ValueFiles @@ -802,9 +1015,10 @@ func unset(source *argoappv1.ApplicationSource, opts unsetOpts) (updated bool, n updated = true } } + if source.Plugin != nil { if len(opts.pluginEnvs) == 0 { - return false, true + return false, !needToUnsetRef } for _, env := range opts.pluginEnvs { err := source.Plugin.RemoveEnvEntry(env) @@ -829,9 +1043,9 @@ func targetObjects(resources []*argoappv1.ResourceDiff) ([]*unstructured.Unstruc return objs, nil } -func getLocalObjects(ctx context.Context, app *argoappv1.Application, local, localRepoRoot, appLabelKey, kubeVersion string, apiVersions []string, kustomizeOptions *argoappv1.KustomizeOptions, - configManagementPlugins []*argoappv1.ConfigManagementPlugin, trackingMethod string) []*unstructured.Unstructured { - manifestStrings := getLocalObjectsString(ctx, app, local, localRepoRoot, appLabelKey, kubeVersion, apiVersions, kustomizeOptions, configManagementPlugins, trackingMethod) +func getLocalObjects(ctx context.Context, app *argoappv1.Application, proj *argoappv1.AppProject, local, localRepoRoot, appLabelKey, kubeVersion string, apiVersions []string, kustomizeOptions *argoappv1.KustomizeOptions, + trackingMethod string) []*unstructured.Unstructured { + manifestStrings := getLocalObjectsString(ctx, app, proj, local, localRepoRoot, appLabelKey, kubeVersion, apiVersions, kustomizeOptions, trackingMethod) objs := make([]*unstructured.Unstructured, len(manifestStrings)) for i := range manifestStrings { obj := unstructured.Unstructured{} @@ -842,20 +1056,21 @@ func getLocalObjects(ctx context.Context, app *argoappv1.Application, local, loc return objs } -func getLocalObjectsString(ctx context.Context, app *argoappv1.Application, local, localRepoRoot, appLabelKey, kubeVersion string, apiVersions []string, kustomizeOptions *argoappv1.KustomizeOptions, - configManagementPlugins []*argoappv1.ConfigManagementPlugin, trackingMethod string) []string { +func getLocalObjectsString(ctx context.Context, app *argoappv1.Application, proj *argoappv1.AppProject, local, localRepoRoot, appLabelKey, kubeVersion string, apiVersions []string, kustomizeOptions *argoappv1.KustomizeOptions, + trackingMethod string) []string { source := app.Spec.GetSource() res, err := repository.GenerateManifests(ctx, local, localRepoRoot, source.TargetRevision, &repoapiclient.ManifestRequest{ - Repo: &argoappv1.Repository{Repo: source.RepoURL}, - AppLabelKey: appLabelKey, - AppName: app.Name, - Namespace: app.Spec.Destination.Namespace, - ApplicationSource: &source, - KustomizeOptions: kustomizeOptions, - KubeVersion: kubeVersion, - ApiVersions: apiVersions, - Plugins: configManagementPlugins, - TrackingMethod: trackingMethod, + Repo: &argoappv1.Repository{Repo: source.RepoURL}, + AppLabelKey: appLabelKey, + AppName: app.Name, + Namespace: app.Spec.Destination.Namespace, + ApplicationSource: &source, + KustomizeOptions: kustomizeOptions, + KubeVersion: kubeVersion, + ApiVersions: apiVersions, + TrackingMethod: trackingMethod, + ProjectName: proj.Name, + ProjectSourceRepos: proj.Spec.SourceRepos, }, true, &git.NoopCredsStore{}, resource.MustParse("0"), nil) errors.CheckError(err) @@ -909,12 +1124,13 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co localRepoRoot string serverSideGenerate bool localIncludes []string + appNamespace string ) shortDesc := "Perform a diff against the target and live state." 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() @@ -925,27 +1141,23 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co clientset := headless.NewClientOrDie(clientOpts, c) conn, appIf := clientset.NewApplicationClientOrDie() defer argoio.Close(conn) - appName, appNs := argo.ParseAppQualifiedName(args[0], "") - app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{ + appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) + app, err := appIf.Get(ctx, &application.ApplicationQuery{ Name: &appName, Refresh: getRefreshType(refresh, hardRefresh), AppNamespace: &appNs, }) errors.CheckError(err) - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning) - } - - resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ApplicationName: &appName, AppNamespace: &appNs}) + resources, err := appIf.ManagedResources(ctx, &application.ResourcesQuery{ApplicationName: &appName, AppNamespace: &appNs}) errors.CheckError(err) conn, settingsIf := clientset.NewSettingsClientOrDie() defer argoio.Close(conn) - argoSettings, err := settingsIf.Get(ctx, &settingspkg.SettingsQuery{}) + argoSettings, err := settingsIf.Get(ctx, &settings.SettingsQuery{}) errors.CheckError(err) diffOption := &DifferenceOption{} if revision != "" { - q := applicationpkg.ApplicationManifestQuery{ + q := application.ApplicationManifestQuery{ Name: &appName, Revision: &revision, AppNamespace: &appNs, @@ -967,17 +1179,19 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co diffOption.serversideRes = res } else { - fmt.Fprintf(os.Stderr, "Warning: local diff without --server-side-generate is deprecated and does not work with plugins. Server-side generation will be the default in v2.6.") + fmt.Fprintf(os.Stderr, "Warning: local diff without --server-side-generate is deprecated and does not work with plugins. Server-side generation will be the default in v2.7.") conn, clusterIf := clientset.NewClusterClientOrDie() 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 } } - foundDiffs := findandPrintDiff(ctx, app, resources, argoSettings, appName, diffOption) + proj := getProject(c, clientOpts, ctx, app.Spec.Project) + foundDiffs := findandPrintDiff(ctx, app, proj.Project, resources, argoSettings, diffOption) if foundDiffs && exitCode { os.Exit(1) } @@ -991,6 +1205,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co command.Flags().StringVar(&localRepoRoot, "local-repo-root", "/", "Path to the repository root. Used together with --local allows setting the repository root") command.Flags().BoolVar(&serverSideGenerate, "server-side-generate", false, "Used with --local, this will send your manifests to the server for diffing") command.Flags().StringArrayVar(&localIncludes, "local-include", []string{"*.yaml", "*.yml", "*.json"}, "Used with --server-side-generate, specify patterns of filenames to send. Matching is based on filename and not path.") + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Only render the difference in namespace") return command } @@ -1005,14 +1220,14 @@ type DifferenceOption struct { } // findandPrintDiff ... Prints difference between application current state and state stored in git or locally, returns boolean as true if difference is found else returns false -func findandPrintDiff(ctx context.Context, app *argoappv1.Application, resources *applicationpkg.ManagedResourcesResponse, argoSettings *settingspkg.Settings, appName string, diffOptions *DifferenceOption) bool { +func findandPrintDiff(ctx context.Context, app *argoappv1.Application, proj *argoappv1.AppProject, resources *application.ManagedResourcesResponse, argoSettings *settings.Settings, diffOptions *DifferenceOption) bool { var foundDiffs bool liveObjs, err := cmdutil.LiveObjects(resources.Items) errors.CheckError(err) items := make([]objKeyLiveTarget, 0) if diffOptions.local != "" { - localObjs := groupObjsByKey(getLocalObjects(ctx, app, diffOptions.local, diffOptions.localRepoRoot, argoSettings.AppLabelKey, diffOptions.cluster.Info.ServerVersion, diffOptions.cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod), liveObjs, app.Spec.Destination.Namespace) - items = groupObjsForDiff(resources, localObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace)) + localObjs := groupObjsByKey(getLocalObjects(ctx, app, proj, diffOptions.local, diffOptions.localRepoRoot, argoSettings.AppLabelKey, diffOptions.cluster.Info.ServerVersion, diffOptions.cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.TrackingMethod), liveObjs, app.Spec.Destination.Namespace) + items = groupObjsForDiff(resources, localObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace), app.Spec.Destination.Namespace) } else if diffOptions.revision != "" { var unstructureds []*unstructured.Unstructured for _, mfst := range diffOptions.res.Manifests { @@ -1021,7 +1236,7 @@ func findandPrintDiff(ctx context.Context, app *argoappv1.Application, resources unstructureds = append(unstructureds, obj) } groupedObjs := groupObjsByKey(unstructureds, liveObjs, app.Spec.Destination.Namespace) - items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.Name) + items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace), app.Spec.Destination.Namespace) } else if diffOptions.serversideRes != nil { var unstructureds []*unstructured.Unstructured for _, mfst := range diffOptions.serversideRes.Manifests { @@ -1030,7 +1245,7 @@ func findandPrintDiff(ctx context.Context, app *argoappv1.Application, resources unstructureds = append(unstructureds, obj) } groupedObjs := groupObjsByKey(unstructureds, liveObjs, app.Spec.Destination.Namespace) - items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.Name) + items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace), app.Spec.Destination.Namespace) } else { for i := range resources.Items { res := resources.Items[i] @@ -1090,7 +1305,7 @@ func findandPrintDiff(ctx context.Context, app *argoappv1.Application, resources return foundDiffs } -func groupObjsForDiff(resources *application.ManagedResourcesResponse, objs map[kube.ResourceKey]*unstructured.Unstructured, items []objKeyLiveTarget, argoSettings *settings.Settings, appName string) []objKeyLiveTarget { +func groupObjsForDiff(resources *application.ManagedResourcesResponse, objs map[kube.ResourceKey]*unstructured.Unstructured, items []objKeyLiveTarget, argoSettings *settings.Settings, appName, namespace string) []objKeyLiveTarget { resourceTracking := argo.NewResourceTracking() for _, res := range resources.Items { var live = &unstructured.Unstructured{} @@ -1105,7 +1320,7 @@ func groupObjsForDiff(resources *application.ManagedResourcesResponse, objs map[ } if local, ok := objs[key]; ok || live != nil { if local != nil && !kube.IsCRD(local) { - err = resourceTracking.SetAppInstance(local, argoSettings.AppLabelKey, appName, "", argoappv1.TrackingMethod(argoSettings.GetTrackingMethod())) + err = resourceTracking.SetAppInstance(local, argoSettings.AppLabelKey, appName, namespace, argoappv1.TrackingMethod(argoSettings.GetTrackingMethod())) errors.CheckError(err) } @@ -1131,6 +1346,8 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. noPrompt bool propagationPolicy string selector string + wait bool + appNamespace string ) var command = &cobra.Command{ Use: "delete APPNAME", @@ -1154,7 +1371,8 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. c.HelpFunc()(c, args) os.Exit(1) } - conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() + acdClient := headless.NewClientOrDie(clientOpts, c) + conn, appIf := acdClient.NewApplicationClientOrDie() defer argoio.Close(conn) var isTerminal bool = isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()) var isConfirmAll bool = false @@ -1172,8 +1390,8 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. } for _, appFullName := range appNames { - appName, appNs := argo.ParseAppQualifiedName(appFullName, "") - appDeleteReq := applicationpkg.ApplicationDeleteRequest{ + appName, appNs := argo.ParseFromQualifiedName(appFullName, appNamespace) + appDeleteReq := application.ApplicationDeleteRequest{ Name: &appName, AppNamespace: &appNs, } @@ -1201,6 +1419,9 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. if lowercaseAnswer == "y" { _, err := appIf.Delete(ctx, &appDeleteReq) errors.CheckError(err) + if wait { + checkForDeleteEvent(ctx, acdClient, appFullName) + } fmt.Printf("application '%s' deleted\n", appFullName) } else { fmt.Println("The command to delete '" + appFullName + "' was cancelled.") @@ -1208,6 +1429,10 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. } else { _, err := appIf.Delete(ctx, &appDeleteReq) errors.CheckError(err) + + if wait { + checkForDeleteEvent(ctx, acdClient, appFullName) + } } } }, @@ -1216,9 +1441,20 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. command.Flags().StringVarP(&propagationPolicy, "propagation-policy", "p", "foreground", "Specify propagation policy for deletion of application's resources. One of: foreground|background") command.Flags().BoolVarP(&noPrompt, "yes", "y", false, "Turn off prompting to confirm cascaded deletion of application resources") command.Flags().StringVarP(&selector, "selector", "l", "", "Delete all apps with matching label. Supports '=', '==', '!=', in, notin, exists & not exists. Matching apps must satisfy all of the specified label constraints.") + command.Flags().BoolVar(&wait, "wait", false, "Wait until deletion of the application(s) completes") + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Namespace where the application will be deleted from") return command } +func checkForDeleteEvent(ctx context.Context, acdClient argocdclient.Client, appFullName string) { + appEventCh := acdClient.WatchApplicationWithRetry(ctx, appFullName, "") + for appEvent := range appEventCh { + if appEvent.Type == k8swatch.Deleted { + return + } + } +} + // Print simple list of application names func printApplicationNames(apps []argoappv1.Application) { for _, app := range apps { @@ -1284,7 +1520,7 @@ func NewApplicationListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() defer argoio.Close(conn) - apps, err := appIf.List(ctx, &applicationpkg.ApplicationQuery{ + apps, err := appIf.List(ctx, &application.ApplicationQuery{ Selector: pointer.String(selector), AppNamespace: &appNamespace, }) @@ -1301,17 +1537,6 @@ func NewApplicationListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co if cluster != "" { appList = argo.FilterByCluster(appList, cluster) } - var appsWithDeprecatedPlugins []string - for _, app := range appList { - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - appsWithDeprecatedPlugins = append(appsWithDeprecatedPlugins, app.Name) - } - } - - if len(appsWithDeprecatedPlugins) > 0 { - log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning) - log.Warnf("The following Applications use deprecated plugins: %s", strings.Join(appsWithDeprecatedPlugins, ", ")) - } switch output { case "yaml", "json": @@ -1337,7 +1562,7 @@ func NewApplicationListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co func formatSyncPolicy(app argoappv1.Application) string { if app.Spec.SyncPolicy == nil || app.Spec.SyncPolicy.Automated == nil { - return "" + return "Manual" } policy := "Auto" if app.Spec.SyncPolicy.Automated.Prune { @@ -1441,10 +1666,12 @@ func getWatchOpts(watch watchOpts) watchOpts { // NewApplicationWaitCommand returns a new instance of an `argocd app wait` command func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( - watch watchOpts - timeout uint - selector string - resources []string + watch watchOpts + timeout uint + selector string + resources []string + output string + appNamespace string ) var command = &cobra.Command{ Use: "wait [APPNAME.. | -l selector]", @@ -1486,14 +1713,18 @@ func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co closer, appIf := acdClient.NewApplicationClientOrDie() defer argoio.Close(closer) if selector != "" { - list, err := appIf.List(ctx, &applicationpkg.ApplicationQuery{Selector: pointer.String(selector)}) + 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 { - _, err := waitOnApplicationStatus(ctx, acdClient, appName, timeout, watch, selectedResources) + // Construct QualifiedName + if appNamespace != "" && !strings.Contains(appName, "/") { + appName = appNamespace + "/" + appName + } + _, _, err := waitOnApplicationStatus(ctx, acdClient, appName, timeout, watch, selectedResources, output) errors.CheckError(err) } }, @@ -1502,10 +1733,13 @@ func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co command.Flags().BoolVar(&watch.health, "health", false, "Wait for health") command.Flags().BoolVar(&watch.suspended, "suspended", false, "Wait for suspended") command.Flags().BoolVar(&watch.degraded, "degraded", false, "Wait for degraded") + command.Flags().BoolVar(&watch.delete, "delete", false, "Wait for delete") command.Flags().StringVarP(&selector, "selector", "l", "", "Wait for apps by label. Supports '=', '==', '!=', in, notin, exists & not exists. Matching apps must satisfy all of the specified label constraints.") command.Flags().StringArrayVar(&resources, "resource", []string{}, fmt.Sprintf("Sync only specific resources as GROUP%[1]sKIND%[1]sNAME or %[2]sGROUP%[1]sKIND%[1]sNAME. Fields may be blank and '*' can be used. This option may be specified repeatedly", resourceFieldDelimiter, resourceExcludeIndicator)) command.Flags().BoolVar(&watch.operation, "operation", false, "Wait for pending operations") command.Flags().UintVar(&timeout, "timeout", defaultCheckTimeoutSeconds, "Time out after this many seconds") + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Only wait for an application in namespace") + command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|tree|tree=detailed") return command } @@ -1517,6 +1751,24 @@ func printAppResources(w io.Writer, app *argoappv1.Application) { } } +func printTreeView(nodeMapping map[string]argoappv1.ResourceNode, parentChildMapping map[string][]string, parentNodes map[string]struct{}, mapNodeNameToResourceState map[string]*resourceState) { + w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) + _, _ = fmt.Fprintf(w, "KIND/NAME\tSTATUS\tHEALTH\tMESSAGE\n") + for uid := range parentNodes { + treeViewAppGet("", nodeMapping, parentChildMapping, nodeMapping[uid], mapNodeNameToResourceState, w) + } + _ = w.Flush() +} + +func printTreeViewDetailed(nodeMapping map[string]argoappv1.ResourceNode, parentChildMapping map[string][]string, parentNodes map[string]struct{}, mapNodeNameToResourceState map[string]*resourceState) { + w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) + fmt.Fprintf(w, "KIND/NAME\tSTATUS\tHEALTH\tAGE\tMESSAGE\tREASON\n") + for uid := range parentNodes { + detailedTreeViewAppGet("", nodeMapping, parentChildMapping, nodeMapping[uid], mapNodeNameToResourceState, w) + } + _ = w.Flush() +} + // NewApplicationSyncCommand returns a new instance of an `argocd app sync` command func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( @@ -1531,6 +1783,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co force bool replace bool serverSideApply bool + applyOutOfSyncOnly bool async bool retryLimit int64 retryBackoffDuration time.Duration @@ -1542,6 +1795,8 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co diffChanges bool diffChangesConfirm bool projects []string + output string + appNamespace string ) var command = &cobra.Command{ Use: "sync [APPNAME... | -l selector | --project project-name]", @@ -1570,17 +1825,13 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co argocd app sync my-app --resource argoproj.io:Rollout:my-namespace/my-rollout`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() - if len(args) == 0 && selector == "" && len(projects) == 0 { - c.HelpFunc()(c, args) os.Exit(1) } - if len(args) > 1 && selector != "" { log.Fatal("Cannot use selector option when application name(s) passed as argument(s)") } - acdClient := headless.NewClientOrDie(clientOpts, c) conn, appIf := acdClient.NewApplicationClientOrDie() defer argoio.Close(conn) @@ -1590,7 +1841,10 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co appNames := args if selector != "" || len(projects) > 0 { - list, err := appIf.List(ctx, &applicationpkg.ApplicationQuery{Selector: pointer.String(selector), Projects: projects}) + list, err := appIf.List(ctx, &application.ApplicationQuery{ + Selector: pointer.String(selector), + AppNamespace: &appNamespace, + Projects: projects}) errors.CheckError(err) // unlike list, we'd want to fail if nothing was found @@ -1611,10 +1865,14 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co } for _, appQualifiedName := range appNames { - appName, appNs := argo.ParseAppQualifiedName(appQualifiedName, "") + // Construct QualifiedName + if appNamespace != "" && !strings.Contains(appQualifiedName, "/") { + appQualifiedName = appNamespace + "/" + appQualifiedName + } + appName, appNs := argo.ParseFromQualifiedName(appQualifiedName, "") if len(selectedLabels) > 0 { - q := applicationpkg.ApplicationManifestQuery{ + q := application.ApplicationManifestQuery{ Name: &appName, AppNamespace: &appNs, Revision: &revision, @@ -1625,6 +1883,8 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co log.Fatal(err) } + fmt.Println("The name of the app is ", appName) + for _, mfst := range res.Manifests { obj, err := argoappv1.UnmarshalToUnstructured(mfst) errors.CheckError(err) @@ -1650,15 +1910,22 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co var localObjsStrings []string diffOption := &DifferenceOption{} - app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{ + app, err := appIf.Get(ctx, &application.ApplicationQuery{ Name: &appName, AppNamespace: &appNs, }) errors.CheckError(err) if app.Spec.HasMultipleSources() { - log.Fatal("argocd cli does not work on multi-source app") - return + if revision != "" { + log.Fatal("argocd cli does not work on multi-source app with --revision flag") + return + } + + if local != "" { + log.Fatal("argocd cli does not work on multi-source app with --local flag") + return + } } // filters out only those resources that needs to be synced @@ -1670,17 +1937,13 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co } if local != "" { - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning) - } - if app.Spec.SyncPolicy != nil && app.Spec.SyncPolicy.Automated != nil && !dryRun { log.Fatal("Cannot use local sync when Automatic Sync Policy is enabled except with --dry-run") } errors.CheckError(err) conn, settingsIf := acdClient.NewSettingsClientOrDie() - argoSettings, err := settingsIf.Get(ctx, &settingspkg.SettingsQuery{}) + argoSettings, err := settingsIf.Get(ctx, &settings.SettingsQuery{}) errors.CheckError(err) argoio.Close(conn) @@ -1689,15 +1952,17 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co cluster, err := clusterIf.Get(ctx, &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server}) errors.CheckError(err) argoio.Close(conn) - localObjsStrings = getLocalObjectsString(ctx, app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.Info.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod) + + proj := getProject(c, clientOpts, ctx, app.Spec.Project) + localObjsStrings = getLocalObjectsString(ctx, app, proj.Project, local, localRepoRoot, argoSettings.AppLabelKey, cluster.Info.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.TrackingMethod) errors.CheckError(err) diffOption.local = local diffOption.localRepoRoot = localRepoRoot diffOption.cluster = cluster } - syncOptionsFactory := func() *applicationpkg.SyncOptions { - syncOptions := applicationpkg.SyncOptions{} + syncOptionsFactory := func() *application.SyncOptions { + syncOptions := application.SyncOptions{} items := make([]string, 0) if replace { items = append(items, common.SyncOptionReplace) @@ -1705,6 +1970,9 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co if serverSideApply { items = append(items, common.SyncOptionServerSideApply) } + if applyOutOfSyncOnly { + items = append(items, common.SyncOptionApplyOutOfSyncOnly) + } if len(items) == 0 { // for prevent send even empty array if not need @@ -1714,7 +1982,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co return &syncOptions } - syncReq := applicationpkg.ApplicationSyncRequest{ + syncReq := application.ApplicationSyncRequest{ Name: &appName, AppNamespace: &appNs, DryRun: &dryRun, @@ -1742,27 +2010,25 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co Backoff: &argoappv1.Backoff{ Duration: retryBackoffDuration.String(), MaxDuration: retryBackoffMaxDuration.String(), - Factor: pointer.Int64Ptr(retryBackoffFactor), + Factor: pointer.Int64(retryBackoffFactor), }, } } if diffChanges { - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning) - } - - resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ + resources, err := appIf.ManagedResources(ctx, &application.ResourcesQuery{ ApplicationName: &appName, AppNamespace: &appNs, }) errors.CheckError(err) conn, settingsIf := acdClient.NewSettingsClientOrDie() defer argoio.Close(conn) - argoSettings, err := settingsIf.Get(ctx, &settingspkg.SettingsQuery{}) + argoSettings, err := settingsIf.Get(ctx, &settings.SettingsQuery{}) errors.CheckError(err) foundDiffs := false fmt.Printf("====== Previewing differences between live and desired state of application %s ======\n", appQualifiedName) - foundDiffs = findandPrintDiff(ctx, app, resources, argoSettings, appQualifiedName, diffOption) + + proj := getProject(c, clientOpts, ctx, app.Spec.Project) + foundDiffs = findandPrintDiff(ctx, app, proj.Project, resources, argoSettings, diffOption) if foundDiffs { if !diffChangesConfirm { yesno := cli.AskToProceed(fmt.Sprintf("Please review changes to application %s shown above. Do you want to continue the sync process? (y/n): ", appQualifiedName)) @@ -1778,15 +2044,15 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co errors.CheckError(err) if !async { - app, err := waitOnApplicationStatus(ctx, acdClient, appQualifiedName, timeout, watchOpts{operation: true}, selectedResources) + app, opState, err := waitOnApplicationStatus(ctx, acdClient, appQualifiedName, timeout, watchOpts{operation: true}, selectedResources, output) errors.CheckError(err) if !dryRun { - if !app.Status.OperationState.Phase.Successful() { - log.Fatalf("Operation has completed with phase: %s", app.Status.OperationState.Phase) + if !opState.Phase.Successful() { + log.Fatalf("Operation has completed with phase: %s", opState.Phase) } else if len(selectedResources) == 0 && app.Status.Sync.Status != argoappv1.SyncStatusCodeSynced { // Only get resources to be pruned if sync was application-wide and final status is not synced - pruningRequired := app.Status.OperationState.SyncResult.Resources.PruningRequired() + pruningRequired := opState.SyncResult.Resources.PruningRequired() if pruningRequired > 0 { log.Fatalf("%d resources require pruning", pruningRequired) } @@ -1811,6 +2077,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co command.Flags().BoolVar(&force, "force", false, "Use a force apply") command.Flags().BoolVar(&replace, "replace", false, "Use a kubectl create/replace instead apply") command.Flags().BoolVar(&serverSideApply, "server-side", false, "Use server-side apply while syncing the application") + command.Flags().BoolVar(&applyOutOfSyncOnly, "apply-out-of-sync-only", false, "Sync only out-of-sync resources") command.Flags().BoolVar(&async, "async", false, "Do not wait for application to sync before continuing") command.Flags().StringVar(&local, "local", "", "Path to a local directory. When this flag is present no git queries will be made") command.Flags().StringVar(&localRepoRoot, "local-repo-root", "/", "Path to the repository root. Used together with --local allows setting the repository root") @@ -1818,13 +2085,15 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co command.Flags().BoolVar(&diffChangesConfirm, "assumeYes", false, "Assume yes as answer for all user queries or prompts") command.Flags().BoolVar(&diffChanges, "preview-changes", false, "Preview difference against the target and live state before syncing app and wait for user confirmation") command.Flags().StringArrayVar(&projects, "project", []string{}, "Sync apps that belong to the specified projects. This option may be specified repeatedly.") + command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|tree|tree=detailed") + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Only sync an application in namespace") return command } -func getAppNamesBySelector(ctx context.Context, appIf applicationpkg.ApplicationServiceClient, selector string) ([]string, error) { +func getAppNamesBySelector(ctx context.Context, appIf application.ApplicationServiceClient, selector string) ([]string, error) { appNames := []string{} if selector != "" { - list, err := appIf.List(ctx, &applicationpkg.ApplicationQuery{Selector: pointer.String(selector)}) + list, err := appIf.List(ctx, &application.ApplicationQuery{Selector: pointer.String(selector)}) if err != nil { return []string{}, err } @@ -1833,7 +2102,7 @@ func getAppNamesBySelector(ctx context.Context, appIf applicationpkg.Application 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 @@ -1969,6 +2238,9 @@ func groupResourceStates(app *argoappv1.Application, selectedResources []*argoap // check if resource health, sync and operation statuses matches watch options func checkResourceStatus(watch watchOpts, healthStatus string, syncStatus string, operationStatus *argoappv1.Operation) bool { + if watch.delete { + return false + } healthCheckPassed := true if watch.suspended && watch.health && watch.degraded { @@ -1981,7 +2253,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) @@ -1998,9 +2270,26 @@ func checkResourceStatus(watch watchOpts, healthStatus string, syncStatus string return synced && healthCheckPassed && operational } +// resourceParentChild gets the latest state of the app and the latest state of the app's resource tree and then +// constructs the necessary data structures to print the app as a tree. +func resourceParentChild(ctx context.Context, acdClient argocdclient.Client, appName string, appNs string) (map[string]argoappv1.ResourceNode, map[string][]string, map[string]struct{}, map[string]*resourceState) { + _, appIf := acdClient.NewApplicationClientOrDie() + mapUidToNode, mapParentToChild, parentNode := parentChildDetails(appIf, ctx, appName, appNs) + app, err := appIf.Get(ctx, &application.ApplicationQuery{Name: pointer.String(appName), AppNamespace: pointer.String(appNs)}) + errors.CheckError(err) + mapNodeNameToResourceState := make(map[string]*resourceState) + for _, res := range getResourceStates(app, nil) { + mapNodeNameToResourceState[res.Kind+"/"+res.Name] = res + } + return mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState +} + const waitFormatString = "%s\t%5s\t%10s\t%10s\t%20s\t%8s\t%7s\t%10s\t%s\n" -func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, appName string, timeout uint, watch watchOpts, selectedResources []*argoappv1.SyncOperationResource) (*argoappv1.Application, error) { +// waitOnApplicationStatus watches an application and blocks until either the desired watch conditions +// are fulfilled or we reach the timeout. Returns the app once desired conditions have been filled. +// Additionally return the operationState at time of fulfilment (which may be different than returned app). +func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, appName string, timeout uint, watch watchOpts, selectedResources []*argoappv1.SyncOperationResource, output string) (*argoappv1.Application, *argoappv1.OperationState, error) { ctx, cancel := context.WithCancel(ctx) defer cancel() @@ -2009,14 +2298,14 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, // time when the sync status lags behind when an operation completes refresh := false - appRealName, appNs := argo.ParseAppQualifiedName(appName, "") + appRealName, appNs := argo.ParseFromQualifiedName(appName, "") printFinalStatus := func(app *argoappv1.Application) *argoappv1.Application { var err error if refresh { conn, appClient := acdClient.NewApplicationClientOrDie() refreshType := string(argoappv1.RefreshTypeNormal) - app, err = appClient.Get(ctx, &applicationpkg.ApplicationQuery{ + app, err = appClient.Get(ctx, &application.ApplicationQuery{ Name: &appRealName, Refresh: &refreshType, AppNamespace: &appNs, @@ -2032,18 +2321,49 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, printOperationResult(app.Status.OperationState) } - if len(app.Status.Resources) > 0 { - fmt.Println() - w := tabwriter.NewWriter(os.Stdout, 5, 0, 2, ' ', 0) - printAppResources(w, app) - _ = w.Flush() + switch output { + case "yaml", "json": + err := PrintResource(app, output) + errors.CheckError(err) + case "wide", "": + if len(app.Status.Resources) > 0 { + fmt.Println() + w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) + printAppResources(w, app) + _ = w.Flush() + } + case "tree": + mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs) + if len(mapUidToNode) > 0 { + fmt.Println() + printTreeView(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState) + } + case "tree=detailed": + mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState := resourceParentChild(ctx, acdClient, appName, appNs) + if len(mapUidToNode) > 0 { + fmt.Println() + printTreeViewDetailed(mapUidToNode, mapParentToChild, parentNode, mapNodeNameToResourceState) + } + default: + errors.CheckError(fmt.Errorf("unknown output format: %s", output)) } return app } if timeout != 0 { time.AfterFunc(time.Duration(timeout)*time.Second, func() { + _, appClient := acdClient.NewApplicationClientOrDie() + app, err := appClient.Get(ctx, &application.ApplicationQuery{ + Name: &appRealName, + AppNamespace: &appNs, + }) + errors.CheckError(err) + fmt.Println() + fmt.Println("This is the state of the app after `wait` timed out:") + printFinalStatus(app) cancel() + fmt.Println() + fmt.Println("The command timed out waiting for the conditions to be met.") }) } @@ -2053,16 +2373,32 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, prevStates := make(map[string]*resourceState) conn, appClient := acdClient.NewApplicationClientOrDie() defer argoio.Close(conn) - app, err := appClient.Get(ctx, &applicationpkg.ApplicationQuery{ + app, err := appClient.Get(ctx, &application.ApplicationQuery{ Name: &appRealName, AppNamespace: &appNs, }) errors.CheckError(err) + + // printFinalStatus() will refresh and update the app object, potentially causing the app's + // status.operationState to be different than the version when we break out of the event loop. + // This means the app.status is unreliable for determining the final state of the operation. + // finalOperationState captures the operationState as it was seen when we met the conditions of + // the wait, so the caller can rely on it to determine the outcome of the operation. + // See: https://github.com/argoproj/argo-cd/issues/5592 + finalOperationState := app.Status.OperationState + appEventCh := acdClient.WatchApplicationWithRetry(ctx, appName, app.ResourceVersion) for appEvent := range appEventCh { app = &appEvent.Application + finalOperationState = app.Status.OperationState operationInProgress := false + + if watch.delete && appEvent.Type == k8swatch.Deleted { + fmt.Printf("Application '%s' deleted\n", app.QualifiedName()) + return nil, nil, nil + } + // consider the operation is in progress if app.Operation != nil { // if it just got requested @@ -2099,7 +2435,7 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, if selectedResourcesAreReady && (!operationInProgress || !watch.operation) { app = printFinalStatus(app) - return app, nil + return app, finalOperationState, nil } newStates := groupResourceStates(app, selectedResources) @@ -2109,7 +2445,7 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, if prevState, found := prevStates[stateKey]; found { if watch.health && prevState.Health != string(health.HealthStatusUnknown) && prevState.Health != string(health.HealthStatusDegraded) && newState.Health == string(health.HealthStatusDegraded) { _ = printFinalStatus(app) - return nil, fmt.Errorf("application '%s' health state has transitioned from %s to %s", appName, prevState.Health, newState.Health) + return nil, finalOperationState, fmt.Errorf("application '%s' health state has transitioned from %s to %s", appName, prevState.Health, newState.Health) } doPrint = prevState.Merge(newState) } else { @@ -2123,17 +2459,17 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, _ = w.Flush() } _ = printFinalStatus(app) - return nil, fmt.Errorf("timed out (%ds) waiting for app %q match desired state", timeout, appName) + return nil, finalOperationState, fmt.Errorf("timed out (%ds) waiting for app %q match desired state", timeout, appName) } // setParameterOverrides updates an existing or appends a new parameter override in the application // the app is assumed to be a helm app and is expected to be in the form: // param=value -func setParameterOverrides(app *argoappv1.Application, parameters []string) { +func setParameterOverrides(app *argoappv1.Application, parameters []string, index int) { if len(parameters) == 0 { return } - source := app.Spec.GetSource() + source := app.Spec.GetSourcePtr(index) var sourceType argoappv1.ApplicationSourceType if st, _ := source.ExplicitType(); st != nil { sourceType = *st @@ -2172,14 +2508,56 @@ func printApplicationHistoryIds(revHistory []argoappv1.RevisionHistory) { // Print a history table for an application. func printApplicationHistoryTable(revHistory []argoappv1.RevisionHistory) { + MAX_ALLOWED_REVISIONS := 7 w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) - _, _ = fmt.Fprintf(w, "ID\tDATE\tREVISION\n") + type history struct { + id int64 + date string + revision string + } + varHistory := map[string][]history{} + varHistoryKeys := []string{} for _, depInfo := range revHistory { - rev := depInfo.Source.TargetRevision - if len(depInfo.Revision) >= 7 { - rev = fmt.Sprintf("%s (%s)", rev, depInfo.Revision[0:7]) + if depInfo.Sources != nil { + for i, sourceInfo := range depInfo.Sources { + rev := sourceInfo.TargetRevision + if len(depInfo.Revisions) == len(depInfo.Sources) && len(depInfo.Revisions[i]) >= MAX_ALLOWED_REVISIONS { + rev = fmt.Sprintf("%s (%s)", rev, depInfo.Revisions[i][0:MAX_ALLOWED_REVISIONS]) + } + if _, ok := varHistory[sourceInfo.RepoURL]; !ok { + varHistoryKeys = append(varHistoryKeys, sourceInfo.RepoURL) + } + varHistory[sourceInfo.RepoURL] = append(varHistory[sourceInfo.RepoURL], history{ + id: depInfo.ID, + date: depInfo.DeployedAt.String(), + revision: rev, + }) + } + } else { + rev := depInfo.Source.TargetRevision + if len(depInfo.Revision) >= MAX_ALLOWED_REVISIONS { + rev = fmt.Sprintf("%s (%s)", rev, depInfo.Revision[0:MAX_ALLOWED_REVISIONS]) + } + if _, ok := varHistory[depInfo.Source.RepoURL]; !ok { + varHistoryKeys = append(varHistoryKeys, depInfo.Source.RepoURL) + } + varHistory[depInfo.Source.RepoURL] = append(varHistory[depInfo.Source.RepoURL], history{ + id: depInfo.ID, + date: depInfo.DeployedAt.String(), + revision: rev, + }) + } + } + for i, key := range varHistoryKeys { + _, _ = fmt.Fprintf(w, "SOURCE\t%s\n", key) + _, _ = fmt.Fprintf(w, "ID\tDATE\tREVISION\n") + for _, history := range varHistory[key] { + _, _ = fmt.Fprintf(w, "%d\t%s\t%s\n", history.id, history.date, history.revision) + } + // Add a newline if it's not the last iteration + if i < len(varHistoryKeys)-1 { + _, _ = fmt.Fprintf(w, "\n") } - _, _ = fmt.Fprintf(w, "%d\t%s\t%s\n", depInfo.ID, depInfo.DeployedAt, rev) } _ = w.Flush() } @@ -2187,7 +2565,8 @@ func printApplicationHistoryTable(revHistory []argoappv1.RevisionHistory) { // NewApplicationHistoryCommand returns a new instance of an `argocd app history` command func NewApplicationHistoryCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( - output string + output string + appNamespace string ) var command = &cobra.Command{ Use: "history APPNAME", @@ -2201,17 +2580,13 @@ func NewApplicationHistoryCommand(clientOpts *argocdclient.ClientOptions) *cobra } conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() defer argoio.Close(conn) - appName, appNs := argo.ParseAppQualifiedName(args[0], "") - app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{ + appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) + app, err := appIf.Get(ctx, &application.ApplicationQuery{ Name: &appName, AppNamespace: &appNs, }) errors.CheckError(err) - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning) - } - if output == "id" { printApplicationHistoryIds(app.Status.History) } else { @@ -2219,6 +2594,7 @@ func NewApplicationHistoryCommand(clientOpts *argocdclient.ClientOptions) *cobra } }, } + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Only show application deployment history in namespace") command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: wide|id") return command } @@ -2243,20 +2619,21 @@ func findRevisionHistory(application *argoappv1.Application, historyId int64) (* // NewApplicationRollbackCommand returns a new instance of an `argocd app rollback` command func NewApplicationRollbackCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( - prune bool - timeout uint + prune bool + timeout uint + output string + appNamespace string ) var command = &cobra.Command{ Use: "rollback APPNAME [ID]", Short: "Rollback application to a previous deployed version by History ID, omitted will Rollback to the previous version", Run: func(c *cobra.Command, args []string) { ctx := c.Context() - if len(args) == 0 { c.HelpFunc()(c, args) os.Exit(1) } - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) var err error depID := -1 if len(args) > 1 { @@ -2266,20 +2643,16 @@ func NewApplicationRollbackCommand(clientOpts *argocdclient.ClientOptions) *cobr acdClient := headless.NewClientOrDie(clientOpts, c) conn, appIf := acdClient.NewApplicationClientOrDie() defer argoio.Close(conn) - app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{ + app, err := appIf.Get(ctx, &application.ApplicationQuery{ Name: &appName, AppNamespace: &appNs, }) errors.CheckError(err) - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning) - } - depInfo, err := findRevisionHistory(app, int64(depID)) errors.CheckError(err) - _, err = appIf.Rollback(ctx, &applicationpkg.ApplicationRollbackRequest{ + _, err = appIf.Rollback(ctx, &application.ApplicationRollbackRequest{ Name: &appName, AppNamespace: &appNs, Id: pointer.Int64(depInfo.ID), @@ -2287,14 +2660,16 @@ func NewApplicationRollbackCommand(clientOpts *argocdclient.ClientOptions) *cobr }) errors.CheckError(err) - _, err = waitOnApplicationStatus(ctx, acdClient, app.QualifiedName(), timeout, watchOpts{ + _, _, err = waitOnApplicationStatus(ctx, acdClient, app.QualifiedName(), timeout, watchOpts{ operation: true, - }, nil) + }, nil, output) errors.CheckError(err) }, } command.Flags().BoolVar(&prune, "prune", false, "Allow deleting unexpected resources") command.Flags().UintVar(&timeout, "timeout", defaultCheckTimeoutSeconds, "Time out after this many seconds") + command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|tree|tree=detailed") + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Rollback application in namespace") return command } @@ -2307,7 +2682,11 @@ func printOperationResult(opState *argoappv1.OperationState) { } if opState.SyncResult != nil { fmt.Printf(printOpFmtStr, "Operation:", "Sync") - fmt.Printf(printOpFmtStr, "Sync Revision:", opState.SyncResult.Revision) + if opState.SyncResult.Sources != nil && opState.SyncResult.Revisions != nil { + fmt.Printf(printOpFmtStr, "Sync Revision:", strings.Join(opState.SyncResult.Revisions, ", ")) + } else { + fmt.Printf(printOpFmtStr, "Sync Revision:", opState.SyncResult.Revision) + } } fmt.Printf(printOpFmtStr, "Phase:", opState.Phase) fmt.Printf(printOpFmtStr, "Start:", opState.StartedAt) @@ -2342,11 +2721,11 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob c.HelpFunc()(c, args) os.Exit(1) } - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + appName, appNs := argo.ParseFromQualifiedName(args[0], "") clientset := headless.NewClientOrDie(clientOpts, c) conn, appIf := clientset.NewApplicationClientOrDie() defer argoio.Close(conn) - resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ + resources, err := appIf.ManagedResources(ctx, &application.ResourcesQuery{ ApplicationName: &appName, AppNamespace: &appNs, }) @@ -2356,16 +2735,12 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob switch source { case "git": if local != "" { - app, err := appIf.Get(context.Background(), &applicationpkg.ApplicationQuery{Name: &appName}) + app, err := appIf.Get(context.Background(), &application.ApplicationQuery{Name: &appName}) errors.CheckError(err) - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning) - } - settingsConn, settingsIf := clientset.NewSettingsClientOrDie() defer argoio.Close(settingsConn) - argoSettings, err := settingsIf.Get(context.Background(), &settingspkg.SettingsQuery{}) + argoSettings, err := settingsIf.Get(context.Background(), &settings.SettingsQuery{}) errors.CheckError(err) clusterConn, clusterIf := clientset.NewClusterClientOrDie() @@ -2373,9 +2748,10 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob cluster, err := clusterIf.Get(context.Background(), &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server}) errors.CheckError(err) - unstructureds = getLocalObjects(context.Background(), app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod) + proj := getProject(c, clientOpts, ctx, app.Spec.Project) + unstructureds = getLocalObjects(context.Background(), app, proj.Project, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.TrackingMethod) } else if revision != "" { - q := applicationpkg.ApplicationManifestQuery{ + q := application.ApplicationManifestQuery{ Name: &appName, AppNamespace: &appNs, Revision: pointer.String(revision), @@ -2428,10 +2804,10 @@ func NewApplicationTerminateOpCommand(clientOpts *argocdclient.ClientOptions) *c c.HelpFunc()(c, args) os.Exit(1) } - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + appName, appNs := argo.ParseFromQualifiedName(args[0], "") conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() defer argoio.Close(conn) - _, err := appIf.TerminateOperation(ctx, &applicationpkg.OperationTerminateRequest{ + _, err := appIf.TerminateOperation(ctx, &application.OperationTerminateRequest{ Name: &appName, AppNamespace: &appNs, }) @@ -2443,6 +2819,9 @@ func NewApplicationTerminateOpCommand(clientOpts *argocdclient.ClientOptions) *c } func NewApplicationEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var ( + appNamespace string + ) var command = &cobra.Command{ Use: "edit APPNAME", Short: "Edit application", @@ -2453,19 +2832,16 @@ func NewApplicationEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co c.HelpFunc()(c, args) os.Exit(1) } - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + + appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() defer argoio.Close(conn) - app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{ + app, err := appIf.Get(ctx, &application.ApplicationQuery{ Name: &appName, AppNamespace: &appNs, }) errors.CheckError(err) - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - log.Warnf(argocommon.ConfigMapPluginCLIDeprecationWarning) - } - appData, err := json.Marshal(app.Spec) errors.CheckError(err) appData, err = yaml.JSONToYAML(appData) @@ -2483,8 +2859,12 @@ func NewApplicationEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co } var appOpts cmdutil.AppOptions - cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts) - _, err = appIf.UpdateSpec(ctx, &applicationpkg.ApplicationUpdateSpecRequest{ + + // do not allow overrides for applications with multiple sources + if !app.Spec.HasMultipleSources() { + cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts, 0) + } + _, err = appIf.UpdateSpec(ctx, &application.ApplicationUpdateSpecRequest{ Name: &appName, Spec: &updatedSpec, Validate: &appOpts.Validate, @@ -2497,22 +2877,25 @@ func NewApplicationEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co }) }, } + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Only edit application in namespace") return command } func NewApplicationPatchCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { - var patch string - var patchType string + var ( + patch string + patchType string + appNamespace string + ) command := cobra.Command{ Use: "patch APPNAME", Short: "Patch application", - Long: `Examples: - # Update an application's source path using json patch - argocd app patch myapplication --patch='[{"op": "replace", "path": "/spec/source/path", "value": "newPath"}]' --type json + Example: ` # Update an application's source path using json patch + argocd app patch myapplication --patch='[{"op": "replace", "path": "/spec/source/path", "value": "newPath"}]' --type json - # Update an application's repository target revision using merge patch - argocd app patch myapplication --patch '{"spec": { "source": { "targetRevision": "master" } }}' --type merge`, + # Update an application's repository target revision using merge patch + argocd app patch myapplication --patch '{"spec": { "source": { "targetRevision": "master" } }}' --type merge`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -2520,11 +2903,11 @@ func NewApplicationPatchCommand(clientOpts *argocdclient.ClientOptions) *cobra.C c.HelpFunc()(c, args) os.Exit(1) } - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() defer argoio.Close(conn) - patchedApp, err := appIf.Patch(ctx, &applicationpkg.ApplicationPatchRequest{ + patchedApp, err := appIf.Patch(ctx, &application.ApplicationPatchRequest{ Name: &appName, Patch: &patch, PatchType: &patchType, @@ -2538,8 +2921,137 @@ func NewApplicationPatchCommand(clientOpts *argocdclient.ClientOptions) *cobra.C fmt.Println(string(yamlBytes)) }, } - + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Only patch application in namespace") command.Flags().StringVar(&patch, "patch", "", "Patch body") command.Flags().StringVar(&patchType, "type", "json", "The type of patch being provided; one of [json merge]") return &command } + +// NewApplicationAddSourceCommand returns a new instance of an `argocd app add-source` command +func NewApplicationAddSourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var ( + appOpts cmdutil.AppOptions + appNamespace string + ) + var command = &cobra.Command{ + Use: "add-source APPNAME", + Short: "Adds a source to the list of sources in the application", + Example: ` # Append a source to the list of sources in the application + argocd app add-source guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook`, + Run: func(c *cobra.Command, args []string) { + ctx := c.Context() + if len(args) != 1 { + c.HelpFunc()(c, args) + os.Exit(1) + } + + argocdClient := headless.NewClientOrDie(clientOpts, c) + conn, appIf := argocdClient.NewApplicationClientOrDie() + defer argoio.Close(conn) + + appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) + + app, err := appIf.Get(ctx, &application.ApplicationQuery{ + Name: &appName, + Refresh: getRefreshType(false, false), + AppNamespace: &appNs, + }) + + errors.CheckError(err) + + if c.Flags() == nil { + errors.CheckError(fmt.Errorf("ApplicationSource needs atleast repoUrl, path or chart or ref field. No source to add.")) + } + + if len(app.Spec.Sources) > 0 { + appSource, _ := cmdutil.ConstructSource(&argoappv1.ApplicationSource{}, appOpts, c.Flags()) + + // sourceIndex is the index at which new source will be appended to spec.Sources + sourceIndex := len(app.Spec.GetSources()) + app.Spec.Sources = append(app.Spec.Sources, *appSource) + + setParameterOverrides(app, appOpts.Parameters, sourceIndex) + + _, err = appIf.UpdateSpec(ctx, &application.ApplicationUpdateSpecRequest{ + Name: &app.Name, + Spec: &app.Spec, + Validate: &appOpts.Validate, + AppNamespace: &appNs, + }) + errors.CheckError(err) + + fmt.Printf("Application '%s' updated successfully\n", app.ObjectMeta.Name) + } else { + errors.CheckError(fmt.Errorf("Cannot add source: application %s does not have spec.sources defined", appName)) + } + }, + } + cmdutil.AddAppFlags(command, &appOpts) + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Namespace of the target application where the source will be appended") + return command +} + +// NewApplicationRemoveSourceCommand returns a new instance of an `argocd app remove-source` command +func NewApplicationRemoveSourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var ( + sourceIndex int + appNamespace string + ) + command := &cobra.Command{ + Use: "remove-source APPNAME", + Short: "Remove a source from multiple sources application. Index starts with 1. Default value is -1.", + Example: ` # Remove the source at index 1 from application's sources. Index starts at 1. + argocd app remove-source myapplication --source-index 1`, + Run: func(c *cobra.Command, args []string) { + ctx := c.Context() + + if len(args) != 1 { + c.HelpFunc()(c, args) + os.Exit(1) + } + + if sourceIndex <= 0 { + errors.CheckError(fmt.Errorf("Index value of source must be greater than 0")) + } + + argocdClient := headless.NewClientOrDie(clientOpts, c) + conn, appIf := argocdClient.NewApplicationClientOrDie() + defer argoio.Close(conn) + + appName, appNs := argo.ParseFromQualifiedName(args[0], appNamespace) + + app, err := appIf.Get(ctx, &application.ApplicationQuery{ + Name: &appName, + Refresh: getRefreshType(false, false), + AppNamespace: &appNs, + }) + errors.CheckError(err) + + if !app.Spec.HasMultipleSources() { + errors.CheckError(fmt.Errorf("Application does not have multiple sources configured")) + } + + if len(app.Spec.GetSources()) == 1 { + errors.CheckError(fmt.Errorf("Cannot remove the only source remaining in the app")) + } + + if len(app.Spec.GetSources()) < sourceIndex { + errors.CheckError(fmt.Errorf("Application does not have source at %d\n", sourceIndex)) + } + + app.Spec.Sources = append(app.Spec.Sources[:sourceIndex-1], app.Spec.Sources[sourceIndex:]...) + + _, err = appIf.UpdateSpec(ctx, &application.ApplicationUpdateSpecRequest{ + Name: &app.Name, + Spec: &app.Spec, + AppNamespace: &appNs, + }) + errors.CheckError(err) + + fmt.Printf("Application '%s' updated successfully\n", app.ObjectMeta.Name) + }, + } + command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Namespace of the target application where the source will be appended") + command.Flags().IntVar(&sourceIndex, "source-index", -1, "Index of the source from the list of sources of the app. Index starts from 1.") + return command +} diff --git a/cmd/argocd/commands/app_actions.go b/cmd/argocd/commands/app_actions.go index 7145e2a52c658..866aed5ae349e 100644 --- a/cmd/argocd/commands/app_actions.go +++ b/cmd/argocd/commands/app_actions.go @@ -4,20 +4,22 @@ import ( "context" "encoding/json" "fmt" + "github.com/argoproj/argo-cd/v2/util/templates" "os" "strconv" "text/tabwriter" "github.com/argoproj/argo-cd/v2/cmd/util" - "github.com/ghodss/yaml" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "k8s.io/utils/pointer" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/headless" argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" applicationpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" + "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/util/argo" "github.com/argoproj/argo-cd/v2/util/errors" @@ -32,11 +34,22 @@ type DisplayedAction struct { Disabled bool } +var ( + appActionExample = templates.Examples(` + # List all the available actions for an application + argocd app actions list APPNAME + + # Run an available action for an application + argocd app actions run APPNAME ACTION --kind KIND [--resource-name RESOURCE] [--namespace NAMESPACE] [--group GROUP] + `) +) + // NewApplicationResourceActionsCommand returns a new instance of an `argocd app actions` command func NewApplicationResourceActionsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ - Use: "actions", - Short: "Manage Resource actions", + Use: "actions", + Short: "Manage Resource actions", + Example: appActionExample, Run: func(c *cobra.Command, args []string) { c.HelpFunc()(c, args) os.Exit(1) @@ -57,6 +70,10 @@ func NewApplicationResourceActionsListCommand(clientOpts *argocdclient.ClientOpt var command = &cobra.Command{ Use: "list APPNAME", Short: "Lists available actions on a resource", + Example: templates.Examples(` + # List all the available actions for an application + argocd app actions list APPNAME + `), } command.Run = func(c *cobra.Command, args []string) { ctx := c.Context() @@ -65,7 +82,7 @@ func NewApplicationResourceActionsListCommand(clientOpts *argocdclient.ClientOpt c.HelpFunc()(c, args) os.Exit(1) } - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + appName, appNs := argo.ParseFromQualifiedName(args[0], "") conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() defer io.Close(conn) resources, err := getActionableResourcesForApplication(appIf, ctx, &appNs, &appName) @@ -135,6 +152,10 @@ func NewApplicationResourceActionsRunCommand(clientOpts *argocdclient.ClientOpti var command = &cobra.Command{ Use: "run APPNAME ACTION", Short: "Runs an available action on resource(s)", + Example: templates.Examples(` + # Run an available action for an application + argocd app actions run APPNAME ACTION --kind KIND [--resource-name RESOURCE] [--namespace NAMESPACE] [--group GROUP] + `), } command.Flags().StringVar(&resourceName, "resource-name", "", "Name of resource") @@ -151,7 +172,7 @@ func NewApplicationResourceActionsRunCommand(clientOpts *argocdclient.ClientOpti c.HelpFunc()(c, args) os.Exit(1) } - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + appName, appNs := argo.ParseFromQualifiedName(args[0], "") actionName := args[1] conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() @@ -202,7 +223,7 @@ func getActionableResourcesForApplication(appIf applicationpkg.ApplicationServic if err != nil { return nil, err } - app.Kind = "Application" + app.Kind = application.ApplicationKind app.APIVersion = "argoproj.io/v1alpha1" appManifest, err := json.Marshal(app) if err != nil { diff --git a/cmd/argocd/commands/app_resource_test.go b/cmd/argocd/commands/app_resource_test.go index 2c94ad7a0f418..5846065141e15 100644 --- a/cmd/argocd/commands/app_resource_test.go +++ b/cmd/argocd/commands/app_resource_test.go @@ -1,13 +1,93 @@ package commands import ( + "bytes" "testing" + "text/tabwriter" "github.com/stretchr/testify/assert" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) +func TestPrintTreeViewAppResources(t *testing.T) { + var nodes [3]v1alpha1.ResourceNode + nodes[0].ResourceRef = v1alpha1.ResourceRef{Group: "", Version: "v1", Kind: "Pod", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5-6trpt", UID: "92c3a5fe-d13e-4ae2-b8ec-c10dd3543b28"} + nodes[0].ParentRefs = []v1alpha1.ResourceRef{{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"}} + nodes[1].ResourceRef = v1alpha1.ResourceRef{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"} + nodes[1].ParentRefs = []v1alpha1.ResourceRef{{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"}} + nodes[2].ResourceRef = v1alpha1.ResourceRef{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"} + var nodeMapping = make(map[string]v1alpha1.ResourceNode) + var mapParentToChild = make(map[string][]string) + var parentNode = make(map[string]struct{}) + for _, node := range nodes { + nodeMapping[node.UID] = node + if len(node.ParentRefs) > 0 { + _, ok := mapParentToChild[node.ParentRefs[0].UID] + if !ok { + var temp []string + mapParentToChild[node.ParentRefs[0].UID] = temp + } + mapParentToChild[node.ParentRefs[0].UID] = append(mapParentToChild[node.ParentRefs[0].UID], node.UID) + } else { + parentNode[node.UID] = struct{}{} + } + } + buf := &bytes.Buffer{} + w := tabwriter.NewWriter(buf, 0, 0, 2, ' ', 0) + + printTreeViewAppResourcesNotOrphaned(nodeMapping, mapParentToChild, parentNode, false, false, w) + if err := w.Flush(); err != nil { + t.Fatal(err) + } + output := buf.String() + + assert.Contains(t, output, "Rollout") + assert.Contains(t, output, "argoproj.io") +} + +func TestPrintTreeViewDetailedAppResources(t *testing.T) { + var nodes [3]v1alpha1.ResourceNode + nodes[0].ResourceRef = v1alpha1.ResourceRef{Group: "", Version: "v1", Kind: "Pod", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5-6trpt", UID: "92c3a5fe-d13e-4ae2-b8ec-c10dd3543b28"} + nodes[0].ParentRefs = []v1alpha1.ResourceRef{{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"}} + nodes[1].ResourceRef = v1alpha1.ResourceRef{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"} + nodes[1].ParentRefs = []v1alpha1.ResourceRef{{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"}} + nodes[2].ResourceRef = v1alpha1.ResourceRef{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"} + nodes[2].Health = &v1alpha1.HealthStatus{ + Status: "Degraded", + Message: "Readiness Gate failed", + } + + var nodeMapping = make(map[string]v1alpha1.ResourceNode) + var mapParentToChild = make(map[string][]string) + var parentNode = make(map[string]struct{}) + for _, node := range nodes { + nodeMapping[node.UID] = node + if len(node.ParentRefs) > 0 { + _, ok := mapParentToChild[node.ParentRefs[0].UID] + if !ok { + var temp []string + mapParentToChild[node.ParentRefs[0].UID] = temp + } + mapParentToChild[node.ParentRefs[0].UID] = append(mapParentToChild[node.ParentRefs[0].UID], node.UID) + } else { + parentNode[node.UID] = struct{}{} + } + } + buf := &bytes.Buffer{} + w := tabwriter.NewWriter(buf, 0, 0, 2, ' ', 0) + + printDetailedTreeViewAppResourcesNotOrphaned(nodeMapping, mapParentToChild, parentNode, false, false, w) + if err := w.Flush(); err != nil { + t.Fatal(err) + } + output := buf.String() + + assert.Contains(t, output, "Rollout") + assert.Contains(t, output, "Degraded") + assert.Contains(t, output, "Readiness Gate failed") +} + func TestPrintResourcesTree(t *testing.T) { tree := v1alpha1.ApplicationTree{ Nodes: []v1alpha1.ResourceNode{ @@ -32,7 +112,7 @@ func TestPrintResourcesTree(t *testing.T) { }, } output, _ := captureOutput(func() error { - printResources(true, false, &tree) + printResources(true, false, &tree, "") return nil }) diff --git a/cmd/argocd/commands/app_resources.go b/cmd/argocd/commands/app_resources.go index 02c1054b6372d..4cffb706ff1bc 100644 --- a/cmd/argocd/commands/app_resources.go +++ b/cmd/argocd/commands/app_resources.go @@ -3,10 +3,10 @@ package commands import ( "fmt" "os" - - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "text/tabwriter" "github.com/argoproj/argo-cd/v2/cmd/util" + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -19,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 { @@ -31,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", @@ -47,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() @@ -54,7 +54,7 @@ func NewApplicationPatchResourceCommand(clientOpts *argocdclient.ClientOptions) c.HelpFunc()(c, args) os.Exit(1) } - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + appName, appNs := argo.ParseFromQualifiedName(args[0], "") conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() defer argoio.Close(conn) @@ -78,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()) @@ -95,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", @@ -109,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() @@ -116,7 +119,7 @@ func NewApplicationDeleteResourceCommand(clientOpts *argocdclient.ClientOptions) c.HelpFunc()(c, args) os.Exit(1) } - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + appName, appNs := argo.ParseFromQualifiedName(args[0], "") conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() defer argoio.Close(conn) @@ -140,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()) @@ -149,50 +153,133 @@ func NewApplicationDeleteResourceCommand(clientOpts *argocdclient.ClientOptions) return command } -func printResources(listAll bool, orphaned bool, appResourceTree *v1alpha1.ApplicationTree) { - w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) - headers := []interface{}{"GROUP", "KIND", "NAMESPACE", "NAME", "ORPHANED"} - fmtStr := "%s\t%s\t%s\t%s\t%s\n" - _, _ = fmt.Fprintf(w, fmtStr, headers...) - if !orphaned || listAll { - for _, res := range appResourceTree.Nodes { - if len(res.ParentRefs) == 0 { - _, _ = fmt.Fprintf(w, fmtStr, res.Group, res.Kind, res.Namespace, res.Name, "No") +func parentChildInfo(nodes []v1alpha1.ResourceNode) (map[string]v1alpha1.ResourceNode, map[string][]string, map[string]struct{}) { + mapUidToNode := make(map[string]v1alpha1.ResourceNode) + mapParentToChild := make(map[string][]string) + parentNode := make(map[string]struct{}) + + for _, node := range nodes { + mapUidToNode[node.UID] = node + + if len(node.ParentRefs) > 0 { + _, ok := mapParentToChild[node.ParentRefs[0].UID] + if !ok { + var temp []string + mapParentToChild[node.ParentRefs[0].UID] = temp } + mapParentToChild[node.ParentRefs[0].UID] = append(mapParentToChild[node.ParentRefs[0].UID], node.UID) + } else { + parentNode[node.UID] = struct{}{} } } - if orphaned || listAll { - for _, res := range appResourceTree.OrphanedNodes { - _, _ = fmt.Fprintf(w, fmtStr, res.Group, res.Kind, res.Namespace, res.Name, "Yes") + return mapUidToNode, mapParentToChild, parentNode +} + +func printDetailedTreeViewAppResourcesNotOrphaned(nodeMapping map[string]v1alpha1.ResourceNode, parentChildMapping map[string][]string, parentNodes map[string]struct{}, orphaned bool, listAll bool, w *tabwriter.Writer) { + for uid := range parentNodes { + detailedTreeViewAppResourcesNotOrphaned("", nodeMapping, parentChildMapping, nodeMapping[uid], w) + } + +} + +func printDetailedTreeViewAppResourcesOrphaned(nodeMapping map[string]v1alpha1.ResourceNode, parentChildMapping map[string][]string, parentNodes map[string]struct{}, orphaned bool, listAll bool, w *tabwriter.Writer) { + for uid := range parentNodes { + detailedTreeViewAppResourcesOrphaned("", nodeMapping, parentChildMapping, nodeMapping[uid], w) + } +} + +func printTreeViewAppResourcesNotOrphaned(nodeMapping map[string]v1alpha1.ResourceNode, parentChildMapping map[string][]string, parentNodes map[string]struct{}, orphaned bool, listAll bool, w *tabwriter.Writer) { + for uid := range parentNodes { + treeViewAppResourcesNotOrphaned("", nodeMapping, parentChildMapping, nodeMapping[uid], w) + } + +} + +func printTreeViewAppResourcesOrphaned(nodeMapping map[string]v1alpha1.ResourceNode, parentChildMapping map[string][]string, parentNodes map[string]struct{}, orphaned bool, listAll bool, w *tabwriter.Writer) { + for uid := range parentNodes { + treeViewAppResourcesOrphaned("", nodeMapping, parentChildMapping, nodeMapping[uid], w) + } +} + +func printResources(listAll bool, orphaned bool, appResourceTree *v1alpha1.ApplicationTree, output string) { + w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) + if output == "tree=detailed" { + fmt.Fprintf(w, "GROUP\tKIND\tNAMESPACE\tNAME\tORPHANED\tAGE\tHEALTH\tREASON\n") + + if !orphaned || listAll { + mapUidToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.Nodes) + printDetailedTreeViewAppResourcesNotOrphaned(mapUidToNode, mapParentToChild, parentNode, orphaned, listAll, w) } + + if orphaned || listAll { + mapUidToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.OrphanedNodes) + printDetailedTreeViewAppResourcesOrphaned(mapUidToNode, mapParentToChild, parentNode, orphaned, listAll, w) + } + + } else if output == "tree" { + fmt.Fprintf(w, "GROUP\tKIND\tNAMESPACE\tNAME\tORPHANED\n") + + if !orphaned || listAll { + mapUidToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.Nodes) + printTreeViewAppResourcesNotOrphaned(mapUidToNode, mapParentToChild, parentNode, orphaned, listAll, w) + } + + if orphaned || listAll { + mapUidToNode, mapParentToChild, parentNode := parentChildInfo(appResourceTree.OrphanedNodes) + printTreeViewAppResourcesOrphaned(mapUidToNode, mapParentToChild, parentNode, orphaned, listAll, w) + } + + } else { + + headers := []interface{}{"GROUP", "KIND", "NAMESPACE", "NAME", "ORPHANED"} + fmtStr := "%s\t%s\t%s\t%s\t%s\n" + _, _ = fmt.Fprintf(w, fmtStr, headers...) + if !orphaned || listAll { + for _, res := range appResourceTree.Nodes { + if len(res.ParentRefs) == 0 { + _, _ = fmt.Fprintf(w, fmtStr, res.Group, res.Kind, res.Namespace, res.Name, "No") + } + } + } + if orphaned || listAll { + for _, res := range appResourceTree.OrphanedNodes { + _, _ = fmt.Fprintf(w, fmtStr, res.Group, res.Kind, res.Namespace, res.Name, "Yes") + } + } + } _ = w.Flush() + } 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", Run: func(c *cobra.Command, args []string) { ctx := c.Context() - if len(args) != 1 { c.HelpFunc()(c, args) os.Exit(1) } listAll := !c.Flag("orphaned").Changed - appName, appNs := argo.ParseAppQualifiedName(args[0], "") + appName, appNs := argo.ParseFromQualifiedName(args[0], "") conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie() defer argoio.Close(conn) appResourceTree, err := appIf.ResourceTree(ctx, &applicationpkg.ResourcesQuery{ ApplicationName: &appName, AppNamespace: &appNs, + Project: &project, }) errors.CheckError(err) - printResources(listAll, orphaned, appResourceTree) + printResources(listAll, orphaned, appResourceTree, output) }, } 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/app_test.go b/cmd/argocd/commands/app_test.go index 104495cb541d0..ec9dcdf0f8e65 100644 --- a/cmd/argocd/commands/app_test.go +++ b/cmd/argocd/commands/app_test.go @@ -1,21 +1,43 @@ package commands import ( + "context" "fmt" + "io" + "net/http" "os" "testing" "time" argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" + accountpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/account" + applicationpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" + applicationsetpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/applicationset" + certificatepkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/certificate" + clusterpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster" + gpgkeypkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/gpgkey" + notificationpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/notification" + projectpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/project" + repocredspkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/repocreds" + repositorypkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/repository" + sessionpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/session" + settingspkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/settings" + versionpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/version" + "github.com/argoproj/argo-cd/v2/pkg/apis/application" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/gitops-engine/pkg/health" "github.com/argoproj/gitops-engine/pkg/utils/kube" + "github.com/coreos/go-oidc/v3/oidc" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/assert" + "golang.org/x/oauth2" 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/util/intstr" + k8swatch "k8s.io/apimachinery/pkg/watch" ) func Test_getInfos(t *testing.T) { @@ -113,6 +135,86 @@ func TestFindRevisionHistoryWithoutPassedId(t *testing.T) { } +func TestPrintTreeViewAppGet(t *testing.T) { + var nodes [3]v1alpha1.ResourceNode + nodes[0].ResourceRef = v1alpha1.ResourceRef{Group: "", Version: "v1", Kind: "Pod", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5-6trpt", UID: "92c3a5fe-d13e-4ae2-b8ec-c10dd3543b28"} + nodes[0].ParentRefs = []v1alpha1.ResourceRef{{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"}} + nodes[1].ResourceRef = v1alpha1.ResourceRef{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"} + nodes[1].ParentRefs = []v1alpha1.ResourceRef{{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"}} + nodes[2].ResourceRef = v1alpha1.ResourceRef{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"} + + var nodeMapping = make(map[string]v1alpha1.ResourceNode) + var mapParentToChild = make(map[string][]string) + var parentNode = make(map[string]struct{}) + + for _, node := range nodes { + nodeMapping[node.UID] = node + + if len(node.ParentRefs) > 0 { + _, ok := mapParentToChild[node.ParentRefs[0].UID] + if !ok { + var temp []string + mapParentToChild[node.ParentRefs[0].UID] = temp + } + mapParentToChild[node.ParentRefs[0].UID] = append(mapParentToChild[node.ParentRefs[0].UID], node.UID) + } else { + parentNode[node.UID] = struct{}{} + } + } + + output, _ := captureOutput(func() error { + printTreeView(nodeMapping, mapParentToChild, parentNode, nil) + return nil + }) + + assert.Contains(t, output, "Pod") + assert.Contains(t, output, "ReplicaSet") + assert.Contains(t, output, "Rollout") + assert.Contains(t, output, "numalogic-rollout-demo-5dcd5457d5-6trpt") +} + +func TestPrintTreeViewDetailedAppGet(t *testing.T) { + var nodes [3]v1alpha1.ResourceNode + nodes[0].ResourceRef = v1alpha1.ResourceRef{Group: "", Version: "v1", Kind: "Pod", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5-6trpt", UID: "92c3a5fe-d13e-4ae2-b8ec-c10dd3543b28"} + nodes[0].Health = &v1alpha1.HealthStatus{Status: "Degraded", Message: "Readiness Gate failed"} + nodes[0].ParentRefs = []v1alpha1.ResourceRef{{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"}} + nodes[1].ResourceRef = v1alpha1.ResourceRef{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"} + nodes[1].ParentRefs = []v1alpha1.ResourceRef{{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"}} + nodes[2].ResourceRef = v1alpha1.ResourceRef{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"} + + var nodeMapping = make(map[string]v1alpha1.ResourceNode) + var mapParentToChild = make(map[string][]string) + var parentNode = make(map[string]struct{}) + + for _, node := range nodes { + nodeMapping[node.UID] = node + + if len(node.ParentRefs) > 0 { + _, ok := mapParentToChild[node.ParentRefs[0].UID] + if !ok { + var temp []string + mapParentToChild[node.ParentRefs[0].UID] = temp + } + mapParentToChild[node.ParentRefs[0].UID] = append(mapParentToChild[node.ParentRefs[0].UID], node.UID) + } else { + parentNode[node.UID] = struct{}{} + } + } + + output, _ := captureOutput(func() error { + printTreeViewDetailed(nodeMapping, mapParentToChild, parentNode, nil) + return nil + }) + + assert.Contains(t, output, "Pod") + assert.Contains(t, output, "ReplicaSet") + assert.Contains(t, output, "Rollout") + assert.Contains(t, output, "numalogic-rollout-demo-5dcd5457d5-6trpt") + assert.Contains(t, output, "Degraded") + assert.Contains(t, output, "Readiness Gate failed") + +} + func TestDefaultWaitOptions(t *testing.T) { watch := watchOpts{ sync: false, @@ -305,8 +407,8 @@ func Test_groupObjsByKey(t *testing.T) { } expected := map[kube.ResourceKey]*unstructured.Unstructured{ - kube.ResourceKey{Group: "", Kind: "Pod", Namespace: "default", Name: "pod-name"}: localObjs[0], - kube.ResourceKey{Group: "apiextensions.k8s.io", Kind: "CustomResourceDefinition", Namespace: "", Name: "certificates.cert-manager.io"}: localObjs[1], + {Group: "", Kind: "Pod", Namespace: "default", Name: "pod-name"}: localObjs[0], + {Group: "apiextensions.k8s.io", Kind: "CustomResourceDefinition", Namespace: "", Name: "certificates.cert-manager.io"}: localObjs[1], } objByKey := groupObjsByKey(localObjs, liveObjs, "default") @@ -320,8 +422,8 @@ func TestFormatSyncPolicy(t *testing.T) { policy := formatSyncPolicy(app) - if policy != "" { - t.Fatalf("Incorrect policy %q, should be ", policy) + if policy != "Manual" { + t.Fatalf("Incorrect policy %q, should be Manual", policy) } }) @@ -455,18 +557,100 @@ func TestPrintApplicationHistoryTable(t *testing.T) { ID: 1, Source: v1alpha1.ApplicationSource{ TargetRevision: "1", + RepoURL: "test", }, }, { ID: 2, Source: v1alpha1.ApplicationSource{ TargetRevision: "2", + RepoURL: "test", }, }, { ID: 3, Source: v1alpha1.ApplicationSource{ TargetRevision: "3", + RepoURL: "test", + }, + }, + } + + output, _ := captureOutput(func() error { + printApplicationHistoryTable(histories) + return nil + }) + + expectation := "SOURCE test\nID DATE REVISION\n1 0001-01-01 00:00:00 +0000 UTC 1\n2 0001-01-01 00:00:00 +0000 UTC 2\n3 0001-01-01 00:00:00 +0000 UTC 3\n" + + if output != expectation { + t.Fatalf("Incorrect print operation output %q, should be %q", output, expectation) + } +} + +func TestPrintApplicationHistoryTableWithMultipleSources(t *testing.T) { + histories := []v1alpha1.RevisionHistory{ + { + ID: 0, + Source: v1alpha1.ApplicationSource{ + TargetRevision: "0", + RepoURL: "test", + }, + }, + { + ID: 1, + Revisions: []string{ + "1a", + "1b", + }, + //added Source just for testing the fuction + Source: v1alpha1.ApplicationSource{ + TargetRevision: "-1", + RepoURL: "ignore", + }, + Sources: v1alpha1.ApplicationSources{ + v1alpha1.ApplicationSource{ + RepoURL: "test-1", + TargetRevision: "1a", + }, + v1alpha1.ApplicationSource{ + RepoURL: "test-2", + TargetRevision: "1b", + }, + }, + }, + { + ID: 2, + Revisions: []string{ + "2a", + "2b", + }, + Sources: v1alpha1.ApplicationSources{ + v1alpha1.ApplicationSource{ + RepoURL: "test-1", + TargetRevision: "2a", + }, + v1alpha1.ApplicationSource{ + RepoURL: "test-2", + TargetRevision: "2b", + }, + }, + }, + { + ID: 3, + Revisions: []string{ + "3a", + "3b", + }, + Sources: v1alpha1.ApplicationSources{ + v1alpha1.ApplicationSource{ + RepoURL: "test-1", + TargetRevision: "3a", + }, + v1alpha1.ApplicationSource{ + RepoURL: "test-2", + TargetRevision: "3b", + }, }, }, } @@ -476,7 +660,7 @@ func TestPrintApplicationHistoryTable(t *testing.T) { return nil }) - expectation := "ID DATE REVISION\n1 0001-01-01 00:00:00 +0000 UTC 1\n2 0001-01-01 00:00:00 +0000 UTC 2\n3 0001-01-01 00:00:00 +0000 UTC 3\n" + expectation := "SOURCE test\nID DATE REVISION\n0 0001-01-01 00:00:00 +0000 UTC 0\n\nSOURCE test-1\nID DATE REVISION\n1 0001-01-01 00:00:00 +0000 UTC 1a\n2 0001-01-01 00:00:00 +0000 UTC 2a\n3 0001-01-01 00:00:00 +0000 UTC 3a\n\nSOURCE test-2\nID DATE REVISION\n1 0001-01-01 00:00:00 +0000 UTC 1b\n2 0001-01-01 00:00:00 +0000 UTC 2b\n3 0001-01-01 00:00:00 +0000 UTC 3b\n" if output != expectation { t.Fatalf("Incorrect print operation output %q, should be %q", output, expectation) @@ -557,11 +741,110 @@ Project: default Server: local Namespace: argocd URL: url -Repo: test -Target: master -Path: /test -Helm Values: path1,path2 -Name Prefix: prefix +Source: +- Repo: test + Target: master + Path: /test + Helm Values: path1,path2 + Name Prefix: prefix +SyncWindow: Sync Denied +Assigned Windows: allow:0 0 * * *:24h,deny:0 0 * * *:24h,allow:0 0 * * *:24h +Sync Policy: Automated (Prune) +Sync Status: OutOfSync from master +Health Status: Progressing (health-message) +` + assert.Equalf(t, expectation, output, "Incorrect print app summary output %q, should be %q", output, expectation) +} + +func TestPrintAppSummaryTable_MultipleSources(t *testing.T) { + output, _ := captureOutput(func() error { + app := &v1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSpec{ + SyncPolicy: &v1alpha1.SyncPolicy{ + Automated: &v1alpha1.SyncPolicyAutomated{ + Prune: true, + }, + }, + Project: "default", + Destination: v1alpha1.ApplicationDestination{Server: "local", Namespace: "argocd"}, + Sources: v1alpha1.ApplicationSources{ + { + RepoURL: "test", + TargetRevision: "master", + Path: "/test", + Helm: &v1alpha1.ApplicationSourceHelm{ + ValueFiles: []string{"path1", "path2"}, + }, + Kustomize: &v1alpha1.ApplicationSourceKustomize{NamePrefix: "prefix"}, + }, { + RepoURL: "test2", + TargetRevision: "master2", + Path: "/test2", + }, + }, + }, + Status: v1alpha1.ApplicationStatus{ + Sync: v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, + }, + Health: v1alpha1.HealthStatus{ + Status: health.HealthStatusProgressing, + Message: "health-message", + }, + }, + } + + windows := &v1alpha1.SyncWindows{ + { + Kind: "allow", + Schedule: "0 0 * * *", + Duration: "24h", + Applications: []string{ + "*-prod", + }, + ManualSync: true, + }, + { + Kind: "deny", + Schedule: "0 0 * * *", + Duration: "24h", + Namespaces: []string{ + "default", + }, + }, + { + Kind: "allow", + Schedule: "0 0 * * *", + Duration: "24h", + Clusters: []string{ + "in-cluster", + "cluster1", + }, + }, + } + + printAppSummaryTable(app, "url", windows) + return nil + }) + + expectation := `Name: argocd/test +Project: default +Server: local +Namespace: argocd +URL: url +Sources: +- Repo: test + Target: master + Path: /test + Helm Values: path1,path2 + Name Prefix: prefix +- Repo: test2 + Target: master2 + Path: /test2 SyncWindow: Sync Denied Assigned Windows: allow:0 0 * * *:24h,deny:0 0 * * *:24h,allow:0 0 * * *:24h Sync Policy: Automated (Prune) @@ -724,6 +1007,14 @@ func TestTargetObjects_invalid(t *testing.T) { assert.Error(t, err) } +func TestCheckForDeleteEvent(t *testing.T) { + + ctx := context.Background() + fakeClient := new(fakeAcdClient) + + checkForDeleteEvent(ctx, fakeClient, "testApp") +} + func TestPrintApplicationNames(t *testing.T) { output, _ := captureOutput(func() error { app := &v1alpha1.Application{ @@ -750,6 +1041,16 @@ func Test_unset(t *testing.T) { "old1=new:tag", "old2=new:tag", }, + Replicas: []v1alpha1.KustomizeReplica{ + { + Name: "my-deployment", + Count: intstr.FromInt(2), + }, + { + Name: "my-statefulset", + Count: intstr.FromInt(4), + }, + }, }, } @@ -767,7 +1068,7 @@ func Test_unset(t *testing.T) { }, }, PassCredentials: true, - Values: "some: yaml", + ValuesObject: &runtime.RawExtension{Raw: []byte("some: yaml")}, ValueFiles: []string{ "values-1.yaml", "values-2.yaml", @@ -826,6 +1127,15 @@ func Test_unset(t *testing.T) { assert.False(t, updated) assert.False(t, nothingToUnset) + assert.Equal(t, 2, len(kustomizeSource.Kustomize.Replicas)) + updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeReplicas: []string{"my-deployment"}}) + assert.Equal(t, 1, len(kustomizeSource.Kustomize.Replicas)) + assert.True(t, updated) + assert.False(t, nothingToUnset) + updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeReplicas: []string{"my-deployment"}}) + assert.False(t, updated) + assert.False(t, nothingToUnset) + assert.Equal(t, 2, len(helmSource.Helm.Parameters)) updated, nothingToUnset = unset(helmSource, unsetOpts{parameters: []string{"name-1"}}) assert.Equal(t, 1, len(helmSource.Helm.Parameters)) @@ -844,9 +1154,9 @@ func Test_unset(t *testing.T) { assert.False(t, updated) assert.False(t, nothingToUnset) - assert.Equal(t, "some: yaml", helmSource.Helm.Values) + assert.Equal(t, "some: yaml", helmSource.Helm.ValuesString()) updated, nothingToUnset = unset(helmSource, unsetOpts{valuesLiteral: true}) - assert.Equal(t, "", helmSource.Helm.Values) + assert.Equal(t, "", helmSource.Helm.ValuesString()) assert.True(t, updated) assert.False(t, nothingToUnset) updated, nothingToUnset = unset(helmSource, unsetOpts{valuesLiteral: true}) @@ -952,49 +1262,49 @@ func TestFilterAppResources(t *testing.T) { } // Resource filters var ( - blankValues = argoappv1.SyncOperationResource{ + blankValues = v1alpha1.SyncOperationResource{ Group: "", Kind: "", Name: "", Namespace: "", Exclude: false} // *:*:* - includeAllResources = argoappv1.SyncOperationResource{ + includeAllResources = v1alpha1.SyncOperationResource{ Group: "*", Kind: "*", Name: "*", Namespace: "", Exclude: false} // !*:*:* - excludeAllResources = argoappv1.SyncOperationResource{ + excludeAllResources = v1alpha1.SyncOperationResource{ Group: "*", Kind: "*", Name: "*", Namespace: "", Exclude: true} // *:Service:* - includeAllServiceResources = argoappv1.SyncOperationResource{ + includeAllServiceResources = v1alpha1.SyncOperationResource{ Group: "*", Kind: "Service", Name: "*", Namespace: "", Exclude: false} // !*:Service:* - excludeAllServiceResources = argoappv1.SyncOperationResource{ + excludeAllServiceResources = v1alpha1.SyncOperationResource{ Group: "*", Kind: "Service", Name: "*", Namespace: "", Exclude: true} // apps:ReplicaSet:replicaSet-name1 - includeReplicaSet1Resource = argoappv1.SyncOperationResource{ + includeReplicaSet1Resource = v1alpha1.SyncOperationResource{ Group: "apps", Kind: "ReplicaSet", Name: "replicaSet-name1", Namespace: "", Exclude: false} // !apps:ReplicaSet:replicaSet-name2 - excludeReplicaSet2Resource = argoappv1.SyncOperationResource{ + excludeReplicaSet2Resource = v1alpha1.SyncOperationResource{ Group: "apps", Kind: "ReplicaSet", Name: "replicaSet-name2", @@ -1043,60 +1353,60 @@ func TestFilterAppResources(t *testing.T) { ) tests := []struct { testName string - selectedResources []*argoappv1.SyncOperationResource - expectedResult []*argoappv1.SyncOperationResource + selectedResources []*v1alpha1.SyncOperationResource + expectedResult []*v1alpha1.SyncOperationResource }{ - //--resource apps:ReplicaSet:replicaSet-name1 --resource *:Service:* + // --resource apps:ReplicaSet:replicaSet-name1 --resource *:Service:* {testName: "Include ReplicaSet replicaSet-name1 resouce and all service resources", - selectedResources: []*argoappv1.SyncOperationResource{&includeAllServiceResources, &includeReplicaSet1Resource}, - expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1, &service1, &service2}, + selectedResources: []*v1alpha1.SyncOperationResource{&includeAllServiceResources, &includeReplicaSet1Resource}, + expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1, &service1, &service2}, }, - //--resource apps:ReplicaSet:replicaSet-name1 --resource !*:Service:* + // --resource apps:ReplicaSet:replicaSet-name1 --resource !*:Service:* {testName: "Include ReplicaSet replicaSet-name1 resouce and exclude all service resources", - selectedResources: []*argoappv1.SyncOperationResource{&excludeAllServiceResources, &includeReplicaSet1Resource}, - expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &deployment}, + selectedResources: []*v1alpha1.SyncOperationResource{&excludeAllServiceResources, &includeReplicaSet1Resource}, + expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &deployment}, }, // --resource !apps:ReplicaSet:replicaSet-name2 --resource !*:Service:* {testName: "Exclude ReplicaSet replicaSet-name2 resouce and all service resources", - selectedResources: []*argoappv1.SyncOperationResource{&excludeReplicaSet2Resource, &excludeAllServiceResources}, - expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &service1, &service2, &deployment}, + selectedResources: []*v1alpha1.SyncOperationResource{&excludeReplicaSet2Resource, &excludeAllServiceResources}, + expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &service1, &service2, &deployment}, }, // --resource !apps:ReplicaSet:replicaSet-name2 {testName: "Exclude ReplicaSet replicaSet-name2 resouce", - selectedResources: []*argoappv1.SyncOperationResource{&excludeReplicaSet2Resource}, - expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1, &job, &service1, &service2, &deployment}, + selectedResources: []*v1alpha1.SyncOperationResource{&excludeReplicaSet2Resource}, + expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1, &job, &service1, &service2, &deployment}, }, // --resource apps:ReplicaSet:replicaSet-name1 {testName: "Include ReplicaSet replicaSet-name1 resouce", - selectedResources: []*argoappv1.SyncOperationResource{&includeReplicaSet1Resource}, - expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1}, + selectedResources: []*v1alpha1.SyncOperationResource{&includeReplicaSet1Resource}, + expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1}, }, // --resource !*:Service:* {testName: "Exclude Service resouces", - selectedResources: []*argoappv1.SyncOperationResource{&excludeAllServiceResources}, - expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &deployment}, + selectedResources: []*v1alpha1.SyncOperationResource{&excludeAllServiceResources}, + expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &deployment}, }, // --resource *:Service:* {testName: "Include Service resouces", - selectedResources: []*argoappv1.SyncOperationResource{&includeAllServiceResources}, - expectedResult: []*argoappv1.SyncOperationResource{&service1, &service2}, + selectedResources: []*v1alpha1.SyncOperationResource{&includeAllServiceResources}, + expectedResult: []*v1alpha1.SyncOperationResource{&service1, &service2}, }, // --resource !*:*:* {testName: "Exclude all resouces", - selectedResources: []*argoappv1.SyncOperationResource{&excludeAllResources}, + selectedResources: []*v1alpha1.SyncOperationResource{&excludeAllResources}, expectedResult: nil, }, // --resource *:*:* {testName: "Include all resouces", - selectedResources: []*argoappv1.SyncOperationResource{&includeAllResources}, - expectedResult: []*argoappv1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &service1, &service2, &deployment}, + selectedResources: []*v1alpha1.SyncOperationResource{&includeAllResources}, + expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &service1, &service2, &deployment}, }, {testName: "No Filters", - selectedResources: []*argoappv1.SyncOperationResource{&blankValues}, + selectedResources: []*v1alpha1.SyncOperationResource{&blankValues}, expectedResult: nil, }, {testName: "Empty Filter", - selectedResources: []*argoappv1.SyncOperationResource{}, + selectedResources: []*v1alpha1.SyncOperationResource{}, expectedResult: nil, }, } @@ -1121,13 +1431,13 @@ func TestParseSelectedResources(t *testing.T) { assert.Equal(t, *operationResources[0], v1alpha1.SyncOperationResource{ Namespace: "", Name: "test", - Kind: "Application", + Kind: application.ApplicationKind, Group: "v1alpha", }) assert.Equal(t, *operationResources[1], v1alpha1.SyncOperationResource{ Namespace: "namespace", Name: "test", - Kind: "Application", + Kind: application.ApplicationKind, Group: "v1alpha", }) assert.Equal(t, *operationResources[2], v1alpha1.SyncOperationResource{ @@ -1200,7 +1510,7 @@ func TestPrintApplicationTableNotWide(t *testing.T) { return nil }) assert.NoError(t, err) - expectation := "NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS\napp-name http://localhost:8080 default prj OutOfSync Healthy \napp-name http://localhost:8080 default prj OutOfSync Healthy \n" + expectation := "NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS\napp-name http://localhost:8080 default prj OutOfSync Healthy Manual \napp-name http://localhost:8080 default prj OutOfSync Healthy Manual \n" assert.Equal(t, output, expectation) } @@ -1236,7 +1546,7 @@ func TestPrintApplicationTableWide(t *testing.T) { return nil }) assert.NoError(t, err) - expectation := "NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET\napp-name http://localhost:8080 default prj OutOfSync Healthy https://github.com/argoproj/argocd-example-apps guestbook 123\napp-name http://localhost:8080 default prj OutOfSync Healthy https://github.com/argoproj/argocd-example-apps guestbook 123\n" + expectation := "NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONS REPO PATH TARGET\napp-name http://localhost:8080 default prj OutOfSync Healthy Manual https://github.com/argoproj/argocd-example-apps guestbook 123\napp-name http://localhost:8080 default prj OutOfSync Healthy Manual https://github.com/argoproj/argocd-example-apps guestbook 123\n" assert.Equal(t, output, expectation) } @@ -1419,8 +1729,8 @@ func TestCheckResourceStatus(t *testing.T) { func Test_hasAppChanged(t *testing.T) { type args struct { - appReq *argoappv1.Application - appRes *argoappv1.Application + appReq *v1alpha1.Application + appRes *v1alpha1.Application upsert bool } tests := []struct { @@ -1482,19 +1792,120 @@ func Test_hasAppChanged(t *testing.T) { } } -func testApp(name, project string, labels map[string]string, annotations map[string]string, finalizers []string) *argoappv1.Application { - return &argoappv1.Application{ +func testApp(name, project string, labels map[string]string, annotations map[string]string, finalizers []string) *v1alpha1.Application { + return &v1alpha1.Application{ ObjectMeta: metav1.ObjectMeta{ Name: name, Labels: labels, Annotations: annotations, Finalizers: finalizers, }, - Spec: argoappv1.ApplicationSpec{ - Source: &argoappv1.ApplicationSource{ + Spec: v1alpha1.ApplicationSpec{ + Source: &v1alpha1.ApplicationSource{ RepoURL: "https://github.com/argoproj/argocd-example-apps.git", }, Project: project, }, } } + +type fakeAcdClient struct{} + +func (c *fakeAcdClient) ClientOptions() argocdclient.ClientOptions { + return argocdclient.ClientOptions{} +} +func (c *fakeAcdClient) HTTPClient() (*http.Client, error) { return nil, nil } +func (c *fakeAcdClient) OIDCConfig(context.Context, *settingspkg.Settings) (*oauth2.Config, *oidc.Provider, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewRepoClient() (io.Closer, repositorypkg.RepositoryServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewRepoClientOrDie() (io.Closer, repositorypkg.RepositoryServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) NewRepoCredsClient() (io.Closer, repocredspkg.RepoCredsServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewRepoCredsClientOrDie() (io.Closer, repocredspkg.RepoCredsServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) NewCertClient() (io.Closer, certificatepkg.CertificateServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewCertClientOrDie() (io.Closer, certificatepkg.CertificateServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) NewClusterClient() (io.Closer, clusterpkg.ClusterServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewClusterClientOrDie() (io.Closer, clusterpkg.ClusterServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) NewGPGKeyClient() (io.Closer, gpgkeypkg.GPGKeyServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewGPGKeyClientOrDie() (io.Closer, gpgkeypkg.GPGKeyServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) NewApplicationClient() (io.Closer, applicationpkg.ApplicationServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewApplicationSetClient() (io.Closer, applicationsetpkg.ApplicationSetServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewApplicationClientOrDie() (io.Closer, applicationpkg.ApplicationServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) NewApplicationSetClientOrDie() (io.Closer, applicationsetpkg.ApplicationSetServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) NewNotificationClient() (io.Closer, notificationpkg.NotificationServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewNotificationClientOrDie() (io.Closer, notificationpkg.NotificationServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) NewSessionClient() (io.Closer, sessionpkg.SessionServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewSessionClientOrDie() (io.Closer, sessionpkg.SessionServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) NewSettingsClient() (io.Closer, settingspkg.SettingsServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewSettingsClientOrDie() (io.Closer, settingspkg.SettingsServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) NewVersionClient() (io.Closer, versionpkg.VersionServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewVersionClientOrDie() (io.Closer, versionpkg.VersionServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) NewProjectClient() (io.Closer, projectpkg.ProjectServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewProjectClientOrDie() (io.Closer, projectpkg.ProjectServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) NewAccountClient() (io.Closer, accountpkg.AccountServiceClient, error) { + return nil, nil, nil +} +func (c *fakeAcdClient) NewAccountClientOrDie() (io.Closer, accountpkg.AccountServiceClient) { + return nil, nil +} +func (c *fakeAcdClient) WatchApplicationWithRetry(ctx context.Context, appName string, revision string) chan *v1alpha1.ApplicationWatchEvent { + appEventsCh := make(chan *v1alpha1.ApplicationWatchEvent) + + go func() { + modifiedEvent := new(v1alpha1.ApplicationWatchEvent) + modifiedEvent.Type = k8swatch.Modified + appEventsCh <- modifiedEvent + deletedEvent := new(v1alpha1.ApplicationWatchEvent) + deletedEvent.Type = k8swatch.Deleted + appEventsCh <- deletedEvent + }() + return appEventsCh +} diff --git a/cmd/argocd/commands/applicationset.go b/cmd/argocd/commands/applicationset.go index 678d5699b9d19..f5ed6a15b6208 100644 --- a/cmd/argocd/commands/applicationset.go +++ b/cmd/argocd/commands/applicationset.go @@ -16,6 +16,7 @@ import ( argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" "github.com/argoproj/argo-cd/v2/pkg/apiclient/applicationset" arogappsetv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/v2/util/argo" "github.com/argoproj/argo-cd/v2/util/cli" "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/grpc" @@ -66,6 +67,10 @@ func NewApplicationSetGetCommand(clientOpts *argocdclient.ClientOptions) *cobra. var command = &cobra.Command{ Use: "get APPSETNAME", Short: "Get ApplicationSet details", + Example: templates.Examples(` + # Get ApplicationSets + argocd appset get APPSETNAME + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -76,8 +81,10 @@ func NewApplicationSetGetCommand(clientOpts *argocdclient.ClientOptions) *cobra. acdClient := headless.NewClientOrDie(clientOpts, c) conn, appIf := acdClient.NewApplicationSetClientOrDie() defer argoio.Close(conn) - appSetName := args[0] - appSet, err := appIf.Get(ctx, &applicationset.ApplicationSetGetQuery{Name: appSetName}) + + appSetName, appSetNs := argo.ParseFromQualifiedName(args[0], "") + + appSet, err := appIf.Get(ctx, &applicationset.ApplicationSetGetQuery{Name: appSetName, AppsetNamespace: appSetNs}) errors.CheckError(err) switch output { @@ -144,7 +151,7 @@ func NewApplicationSetCreateCommand(clientOpts *argocdclient.ClientOptions) *cob defer argoio.Close(conn) // Get app before creating to see if it is being updated or no change - existing, err := appIf.Get(ctx, &applicationset.ApplicationSetGetQuery{Name: appset.Name}) + existing, err := appIf.Get(ctx, &applicationset.ApplicationSetGetQuery{Name: appset.Name, AppsetNamespace: appset.Namespace}) if grpc.UnwrapGRPCStatus(err).Code() != codes.NotFound { errors.CheckError(err) } @@ -176,9 +183,10 @@ func NewApplicationSetCreateCommand(clientOpts *argocdclient.ClientOptions) *cob // NewApplicationSetListCommand returns a new instance of an `argocd appset list` command func NewApplicationSetListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( - output string - selector string - projects []string + output string + selector string + projects []string + appSetNamespace string ) var command = &cobra.Command{ Use: "list", @@ -192,7 +200,7 @@ func NewApplicationSetListCommand(clientOpts *argocdclient.ClientOptions) *cobra conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationSetClientOrDie() defer argoio.Close(conn) - appsets, err := appIf.List(ctx, &applicationset.ApplicationSetListQuery{Selector: selector, Projects: projects}) + appsets, err := appIf.List(ctx, &applicationset.ApplicationSetListQuery{Selector: selector, Projects: projects, AppsetNamespace: appSetNamespace}) errors.CheckError(err) appsetList := appsets.Items @@ -213,6 +221,7 @@ func NewApplicationSetListCommand(clientOpts *argocdclient.ClientOptions) *cobra command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: wide|name|json|yaml") command.Flags().StringVarP(&selector, "selector", "l", "", "List applicationsets by label") command.Flags().StringArrayVarP(&projects, "project", "p", []string{}, "Filter by project name") + command.Flags().StringVarP(&appSetNamespace, "appset-namespace", "N", "", "Only list applicationsets in namespace") return command } @@ -245,18 +254,22 @@ func NewApplicationSetDeleteCommand(clientOpts *argocdclient.ClientOptions) *cob if promptFlag.Changed && promptFlag.Value.String() == "true" { noPrompt = true } - for _, appsetName := range args { + for _, appSetQualifiedName := range args { + + appSetName, appSetNs := argo.ParseFromQualifiedName(appSetQualifiedName, "") + appsetDeleteReq := applicationset.ApplicationSetDeleteRequest{ - Name: appsetName, + Name: appSetName, + AppsetNamespace: appSetNs, } if isTerminal && !noPrompt { var lowercaseAnswer string if numOfApps == 1 { - lowercaseAnswer = cli.AskToProceedS("Are you sure you want to delete '" + appsetName + "' and all its Applications? [y/n] ") + lowercaseAnswer = cli.AskToProceedS("Are you sure you want to delete '" + appSetQualifiedName + "' and all its Applications? [y/n] ") } else { if !isConfirmAll { - lowercaseAnswer = cli.AskToProceedS("Are you sure you want to delete '" + appsetName + "' and all its Applications? [y/n/A] where 'A' is to delete all specified ApplicationSets and their Applications without prompting") + lowercaseAnswer = cli.AskToProceedS("Are you sure you want to delete '" + appSetQualifiedName + "' and all its Applications? [y/n/A] where 'A' is to delete all specified ApplicationSets and their Applications without prompting") if lowercaseAnswer == "a" || lowercaseAnswer == "all" { lowercaseAnswer = "y" isConfirmAll = true @@ -268,9 +281,9 @@ func NewApplicationSetDeleteCommand(clientOpts *argocdclient.ClientOptions) *cob if lowercaseAnswer == "y" || lowercaseAnswer == "yes" { _, err := appIf.Delete(ctx, &appsetDeleteReq) errors.CheckError(err) - fmt.Printf("applicationset '%s' deleted\n", appsetName) + fmt.Printf("applicationset '%s' deleted\n", appSetQualifiedName) } else { - fmt.Println("The command to delete '" + appsetName + "' was cancelled.") + fmt.Println("The command to delete '" + appSetQualifiedName + "' was cancelled.") } } else { _, err := appIf.Delete(ctx, &appsetDeleteReq) @@ -286,7 +299,7 @@ func NewApplicationSetDeleteCommand(clientOpts *argocdclient.ClientOptions) *cob // Print simple list of application names func printApplicationSetNames(apps []arogappsetv1.ApplicationSet) { for _, app := range apps { - fmt.Println(app.Name) + fmt.Println(app.QualifiedName()) } } @@ -294,12 +307,12 @@ func printApplicationSetNames(apps []arogappsetv1.ApplicationSet) { func printApplicationSetTable(apps []arogappsetv1.ApplicationSet, output *string) { w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) var fmtStr string - headers := []interface{}{"NAME", "NAMESPACE", "PROJECT", "SYNCPOLICY", "CONDITIONS"} + headers := []interface{}{"NAME", "PROJECT", "SYNCPOLICY", "CONDITIONS"} if *output == "wide" { - fmtStr = "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" + fmtStr = "%s\t%s\t%s\t%s\t%s\t%s\t%s\n" headers = append(headers, "REPO", "PATH", "TARGET") } else { - fmtStr = "%s\t%s\t%s\t%s\t%s\n" + fmtStr = "%s\t%s\t%s\t%s\n" } _, _ = fmt.Fprintf(w, fmtStr, headers...) for _, app := range apps { @@ -310,8 +323,7 @@ func printApplicationSetTable(apps []arogappsetv1.ApplicationSet, output *string } } vals := []interface{}{ - app.ObjectMeta.Name, - app.ObjectMeta.Namespace, + app.QualifiedName(), app.Spec.Template.Spec.Project, app.Spec.SyncPolicy, conditions, @@ -334,25 +346,30 @@ func getServerForAppSet(appSet *arogappsetv1.ApplicationSet) string { func printAppSetSummaryTable(appSet *arogappsetv1.ApplicationSet) { source := appSet.Spec.Template.Spec.GetSource() - fmt.Printf(printOpFmtStr, "Name:", appSet.Name) + fmt.Printf(printOpFmtStr, "Name:", appSet.QualifiedName()) fmt.Printf(printOpFmtStr, "Project:", appSet.Spec.Template.Spec.GetProject()) fmt.Printf(printOpFmtStr, "Server:", getServerForAppSet(appSet)) fmt.Printf(printOpFmtStr, "Namespace:", appSet.Spec.Template.Spec.Destination.Namespace) - fmt.Printf(printOpFmtStr, "Repo:", source.RepoURL) - fmt.Printf(printOpFmtStr, "Target:", source.TargetRevision) - fmt.Printf(printOpFmtStr, "Path:", source.Path) + if !appSet.Spec.Template.Spec.HasMultipleSources() { + fmt.Println("Source:") + } else { + fmt.Println("Sources:") + } printAppSourceDetails(&source) - var syncPolicy string - if appSet.Spec.SyncPolicy != nil && appSet.Spec.Template.Spec.SyncPolicy.Automated != nil { - syncPolicy = "Automated" - if appSet.Spec.Template.Spec.SyncPolicy.Automated.Prune { - syncPolicy += " (Prune)" + var ( + syncPolicyStr string + syncPolicy = appSet.Spec.Template.Spec.SyncPolicy + ) + if syncPolicy != nil && syncPolicy.Automated != nil { + syncPolicyStr = "Automated" + if syncPolicy.Automated.Prune { + syncPolicyStr += " (Prune)" } } else { - syncPolicy = "" + syncPolicyStr = "" } - fmt.Printf(printOpFmtStr, "SyncPolicy:", syncPolicy) + fmt.Printf(printOpFmtStr, "SyncPolicy:", syncPolicyStr) } diff --git a/cmd/argocd/commands/applicationset_test.go b/cmd/argocd/commands/applicationset_test.go index 9937b183e5c29..7740c95a4e63b 100644 --- a/cmd/argocd/commands/applicationset_test.go +++ b/cmd/argocd/commands/applicationset_test.go @@ -1,25 +1,32 @@ package commands import ( + "io" + "os" "testing" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - arogappsetv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func TestPrintApplicationSetNames(t *testing.T) { output, _ := captureOutput(func() error { - appSet := &arogappsetv1.ApplicationSet{ + appSet := &v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "test", }, } - printApplicationSetNames([]arogappsetv1.ApplicationSet{*appSet, *appSet}) + appSet2 := &v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "team-one", + Name: "test", + }, + } + printApplicationSetNames([]v1alpha1.ApplicationSet{*appSet, *appSet2}) return nil }) - expectation := "test\ntest\n" + expectation := "test\nteam-one/test\n" if output != expectation { t.Fatalf("Incorrect print params output %q, should be %q", output, expectation) } @@ -27,44 +34,200 @@ func TestPrintApplicationSetNames(t *testing.T) { func TestPrintApplicationSetTable(t *testing.T) { output, err := captureOutput(func() error { - app := &arogappsetv1.ApplicationSet{ + app := &v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "app-name", }, - Spec: arogappsetv1.ApplicationSetSpec{ - Generators: []arogappsetv1.ApplicationSetGenerator{ - arogappsetv1.ApplicationSetGenerator{ - Git: &arogappsetv1.GitGenerator{ + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ + { + Git: &v1alpha1.GitGenerator{ + RepoURL: "https://github.com/argoproj/argo-cd.git", + Revision: "head", + Directories: []v1alpha1.GitDirectoryGeneratorItem{ + { + Path: "applicationset/examples/git-generator-directory/cluster-addons/*", + }, + }, + }, + }, + }, + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ + Project: "default", + }, + }, + }, + Status: v1alpha1.ApplicationSetStatus{ + Conditions: []v1alpha1.ApplicationSetCondition{ + { + Status: v1alpha1.ApplicationSetConditionStatusTrue, + Type: v1alpha1.ApplicationSetConditionResourcesUpToDate, + }, + }, + }, + } + + app2 := &v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app-name", + Namespace: "team-two", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ + { + Git: &v1alpha1.GitGenerator{ RepoURL: "https://github.com/argoproj/argo-cd.git", Revision: "head", - Directories: []arogappsetv1.GitDirectoryGeneratorItem{ - arogappsetv1.GitDirectoryGeneratorItem{ + Directories: []v1alpha1.GitDirectoryGeneratorItem{ + { Path: "applicationset/examples/git-generator-directory/cluster-addons/*", }, }, }, }, }, - Template: arogappsetv1.ApplicationSetTemplate{ + Template: v1alpha1.ApplicationSetTemplate{ Spec: v1alpha1.ApplicationSpec{ Project: "default", }, }, }, - Status: arogappsetv1.ApplicationSetStatus{ - Conditions: []arogappsetv1.ApplicationSetCondition{ - arogappsetv1.ApplicationSetCondition{ + Status: v1alpha1.ApplicationSetStatus{ + Conditions: []v1alpha1.ApplicationSetCondition{ + { Status: v1alpha1.ApplicationSetConditionStatusTrue, - Type: arogappsetv1.ApplicationSetConditionResourcesUpToDate, + Type: v1alpha1.ApplicationSetConditionResourcesUpToDate, }, }, }, } output := "table" - printApplicationSetTable([]arogappsetv1.ApplicationSet{*app, *app}, &output) + printApplicationSetTable([]v1alpha1.ApplicationSet{*app, *app2}, &output) return nil }) assert.NoError(t, err) - expectation := "NAME NAMESPACE PROJECT SYNCPOLICY CONDITIONS\napp-name default nil [{ResourcesUpToDate True }]\napp-name default nil [{ResourcesUpToDate True }]\n" + expectation := "NAME PROJECT SYNCPOLICY CONDITIONS\napp-name default nil [{ResourcesUpToDate True }]\nteam-two/app-name default nil [{ResourcesUpToDate True }]\n" assert.Equal(t, expectation, output) } + +func TestPrintAppSetSummaryTable(t *testing.T) { + baseAppSet := &v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app-name", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Generators: []v1alpha1.ApplicationSetGenerator{ + { + Git: &v1alpha1.GitGenerator{ + RepoURL: "https://github.com/argoproj/argo-cd.git", + Revision: "head", + Directories: []v1alpha1.GitDirectoryGeneratorItem{ + { + Path: "applicationset/examples/git-generator-directory/cluster-addons/*", + }, + }, + }, + }, + }, + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ + Project: "default", + }, + }, + }, + Status: v1alpha1.ApplicationSetStatus{ + Conditions: []v1alpha1.ApplicationSetCondition{ + { + Status: v1alpha1.ApplicationSetConditionStatusTrue, + Type: v1alpha1.ApplicationSetConditionResourcesUpToDate, + }, + }, + }, + } + + appsetSpecSyncPolicy := baseAppSet.DeepCopy() + appsetSpecSyncPolicy.Spec.SyncPolicy = &v1alpha1.ApplicationSetSyncPolicy{ + PreserveResourcesOnDeletion: true, + } + + appSetTemplateSpecSyncPolicy := baseAppSet.DeepCopy() + appSetTemplateSpecSyncPolicy.Spec.Template.Spec.SyncPolicy = &v1alpha1.SyncPolicy{ + Automated: &v1alpha1.SyncPolicyAutomated{ + SelfHeal: true, + }, + } + + appSetBothSyncPolicies := baseAppSet.DeepCopy() + appSetBothSyncPolicies.Spec.SyncPolicy = &v1alpha1.ApplicationSetSyncPolicy{ + PreserveResourcesOnDeletion: true, + } + appSetBothSyncPolicies.Spec.Template.Spec.SyncPolicy = &v1alpha1.SyncPolicy{ + Automated: &v1alpha1.SyncPolicyAutomated{ + SelfHeal: true, + }, + } + + for _, tt := range []struct { + name string + appSet *v1alpha1.ApplicationSet + expectedOutput string + }{ + { + name: "appset with only spec.syncPolicy set", + appSet: appsetSpecSyncPolicy, + expectedOutput: `Name: app-name +Project: default +Server: +Namespace: +Source: +- Repo: + Target: +SyncPolicy: +`, + }, + { + name: "appset with only spec.template.spec.syncPolicy set", + appSet: appSetTemplateSpecSyncPolicy, + expectedOutput: `Name: app-name +Project: default +Server: +Namespace: +Source: +- Repo: + Target: +SyncPolicy: Automated +`, + }, + { + name: "appset with both spec.SyncPolicy and spec.template.spec.syncPolicy set", + appSet: appSetBothSyncPolicies, + expectedOutput: `Name: app-name +Project: default +Server: +Namespace: +Source: +- Repo: + Target: +SyncPolicy: Automated +`, + }, + } { + t.Run(tt.name, func(t *testing.T) { + oldStdout := os.Stdout + defer func() { + os.Stdout = oldStdout + }() + + r, w, _ := os.Pipe() + os.Stdout = w + + printAppSetSummaryTable(tt.appSet) + w.Close() + + out, err := io.ReadAll(r) + assert.NoError(t, err) + assert.Equal(t, tt.expectedOutput, string(out)) + }) + } +} diff --git a/cmd/argocd/commands/bcrypt.go b/cmd/argocd/commands/bcrypt.go index 2aaf94fe9450d..6d8f87fd447a5 100644 --- a/cmd/argocd/commands/bcrypt.go +++ b/cmd/argocd/commands/bcrypt.go @@ -8,14 +8,16 @@ import ( "golang.org/x/crypto/bcrypt" ) -// bcryptCmd represents the bcrypt command +// NewBcryptCmd represents the bcrypt command func NewBcryptCmd() *cobra.Command { var ( password string ) var bcryptCmd = &cobra.Command{ Use: "bcrypt", - Short: "Generate bcrypt hash for the admin password", + Short: "Generate bcrypt hash for any password", + Example: `# Generate bcrypt hash for any password +argocd account bcrypt --password YOUR_PASSWORD`, Run: func(cmd *cobra.Command, args []string) { bytePassword := []byte(password) // Hashing the password diff --git a/cmd/argocd/commands/bcrypt_test.go b/cmd/argocd/commands/bcrypt_test.go index c5949977a1425..ec00a73b0dcba 100644 --- a/cmd/argocd/commands/bcrypt_test.go +++ b/cmd/argocd/commands/bcrypt_test.go @@ -12,7 +12,7 @@ func TestGeneratePassword(t *testing.T) { bcryptCmd := NewBcryptCmd() bcryptCmd.SetArgs([]string{"--password", "abc"}) output := new(bytes.Buffer) - bcryptCmd.SetOutput(output) + bcryptCmd.SetOut(output) err := bcryptCmd.Execute() if err != nil { return diff --git a/cmd/argocd/commands/cert.go b/cmd/argocd/commands/cert.go index 17f13a87d2a7d..d443d57e337d4 100644 --- a/cmd/argocd/commands/cert.go +++ b/cmd/argocd/commands/cert.go @@ -130,12 +130,12 @@ func NewCertAddTLSCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command } }, } - command.Flags().StringVar(&fromFile, "from", "", "read TLS certificate data from file (default is to read from stdin)") + command.Flags().StringVar(&fromFile, "from", "", "Read TLS certificate data from file (default is to read from stdin)") command.Flags().BoolVar(&upsert, "upsert", false, "Replace existing TLS certificate if certificate is different in input") return command } -// NewCertAddCommand returns a new instance of an `argocd cert add` command +// NewCertAddSSHCommand returns a new instance of an `argocd cert add` command func NewCertAddSSHCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( fromFile string @@ -300,9 +300,9 @@ func NewCertListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { } command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide") - command.Flags().StringVar(&sortOrder, "sort", "", "set display sort order for output format wide. One of: hostname|type") - command.Flags().StringVar(&certType, "cert-type", "", "only list certificates of given type, valid: 'ssh','https'") - command.Flags().StringVar(&hostNamePattern, "hostname-pattern", "", "only list certificates for hosts matching given glob-pattern") + command.Flags().StringVar(&sortOrder, "sort", "", "Set display sort order for output format wide. One of: hostname|type") + command.Flags().StringVar(&certType, "cert-type", "", "Only list certificates of given type, valid: 'ssh','https'") + command.Flags().StringVar(&hostNamePattern, "hostname-pattern", "", "Only list certificates for hosts matching given glob-pattern") return command } diff --git a/cmd/argocd/commands/cluster.go b/cmd/argocd/commands/cluster.go index fa8a50d05c25f..f203b82ae9ac0 100644 --- a/cmd/argocd/commands/cluster.go +++ b/cmd/argocd/commands/cluster.go @@ -93,9 +93,17 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie cmdutil.PrintKubeContexts(configAccess) os.Exit(1) } + + if clusterOpts.InCluster && clusterOpts.ClusterEndpoint != "" { + log.Fatal("Can only use one of --in-cluster or --cluster-endpoint") + return + } + contextName := args[0] conf, err := getRestConfig(pathOpts, contextName) errors.CheckError(err) + clientset, err := kubernetes.NewForConfig(conf) + errors.CheckError(err) managerBearerToken := "" var awsAuthConf *argoappv1.AWSAuthConfig var execProviderConf *argoappv1.ExecProviderConfig @@ -103,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{ @@ -114,13 +123,10 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie } } else { // Install RBAC resources for managing the cluster - clientset, err := kubernetes.NewForConfig(conf) - errors.CheckError(err) if clusterOpts.ServiceAccount != "" { managerBearerToken, err = clusterauth.GetServiceAccountBearerToken(clientset, clusterOpts.SystemNamespace, clusterOpts.ServiceAccount, common.BearerTokenTimeout) } else { isTerminal := isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()) - if isTerminal && !skipConfirmation { accessLevel := "cluster" if len(clusterOpts.Namespaces) > 0 { @@ -147,9 +153,18 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie contextName = clusterOpts.Name } clst := cmdutil.NewCluster(contextName, clusterOpts.Namespaces, clusterOpts.ClusterResources, conf, managerBearerToken, awsAuthConf, execProviderConf, labelsMap, annotationsMap) - if clusterOpts.InCluster { + if clusterOpts.InClusterEndpoint() { clst.Server = argoappv1.KubernetesInternalAPIServerAddr + } else if clusterOpts.ClusterEndpoint == string(cmdutil.KubePublicEndpoint) { + endpoint, err := cmdutil.GetKubePublicEndpoint(clientset) + if err != nil || len(endpoint) == 0 { + log.Warnf("Failed to find the cluster endpoint from kube-public data: %v", err) + log.Infof("Falling back to the endpoint '%s' as listed in the kubeconfig context", clst.Server) + endpoint = clst.Server + } + clst.Server = endpoint } + if clusterOpts.Shard >= 0 { clst.Shard = &clusterOpts.Shard } @@ -471,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/common.go b/cmd/argocd/commands/common.go index b7529f768a69a..849b9a48f02b6 100644 --- a/cmd/argocd/commands/common.go +++ b/cmd/argocd/commands/common.go @@ -5,7 +5,7 @@ import ( "fmt" "reflect" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" ) const ( diff --git a/cmd/argocd/commands/completion.go b/cmd/argocd/commands/completion.go index 5e587283375ac..7d3f5675ee95e 100644 --- a/cmd/argocd/commands/completion.go +++ b/cmd/argocd/commands/completion.go @@ -204,8 +204,20 @@ To access completions in your current shell, run $ source <(argocd completion bash) Alternatively, write it to a file and source in .bash_profile -For zsh, output to a file in a directory referenced by the $fpath shell -variable. +For zsh, add the following to your ~/.zshrc file: +source <(argocd completion zsh) +compdef _argocd argocd + +Optionally, also add the following, in case you are getting errors involving compdef & compinit such as command not found: compdef: +autoload -Uz compinit +compinit +`, + Example: `# For bash +$ source <(argocd completion bash) + +# For zsh +$ argocd completion zsh > _argocd +$ source _argocd `, Run: func(cmd *cobra.Command, args []string) { if len(args) != 1 { diff --git a/cmd/argocd/commands/context.go b/cmd/argocd/commands/context.go index ec12aa380cd58..51d003b4df9df 100644 --- a/cmd/argocd/commands/context.go +++ b/cmd/argocd/commands/context.go @@ -22,6 +22,14 @@ func NewContextCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { Use: "context [CONTEXT]", Aliases: []string{"ctx"}, Short: "Switch between contexts", + Example: `# List Argo CD Contexts +argocd context + +# Switch Argo CD context +argocd context cd.argoproj.io + +# Delete Argo CD context +argocd context cd.argoproj.io --delete`, Run: func(c *cobra.Command, args []string) { localCfg, err := localconfig.ReadLocalConfig(clientOpts.ConfigPath) 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 ba72cd5bd2072..eca3cb0fb498a 100644 --- a/cmd/argocd/commands/headless/headless.go +++ b/cmd/argocd/commands/headless/headless.go @@ -11,12 +11,14 @@ import ( "github.com/spf13/cobra" "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/initialize" + "github.com/argoproj/argo-cd/v2/common" "github.com/alicebob/miniredis/v2" - "github.com/go-redis/redis/v8" "github.com/golang/protobuf/ptypes/empty" + "github.com/redis/go-redis/v9" log "github.com/sirupsen/logrus" "github.com/spf13/pflag" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/kubernetes" cache2 "k8s.io/client-go/tools/cache" @@ -38,11 +40,14 @@ import ( ) type forwardCacheClient struct { - namespace string - context string - init sync.Once - client cache.CacheClient - err error + namespace string + context string + init sync.Once + client cache.CacheClient + compression cache.RedisCompressionType + err error + redisHaProxyName string + redisName string } func (c *forwardCacheClient) doLazy(action func(client cache.CacheClient) error) error { @@ -50,15 +55,17 @@ func (c *forwardCacheClient) doLazy(action func(client cache.CacheClient) error) overrides := clientcmd.ConfigOverrides{ CurrentContext: c.context, } + redisHaProxyPodLabelSelector := common.LabelKeyAppName + "=" + c.redisHaProxyName + redisPodLabelSelector := common.LabelKeyAppName + "=" + c.redisName redisPort, err := kubeutil.PortForward(6379, c.namespace, &overrides, - "app.kubernetes.io/name=argocd-redis-ha-haproxy", "app.kubernetes.io/name=argocd-redis") + redisHaProxyPodLabelSelector, redisPodLabelSelector) if err != nil { c.err = err return } redisClient := redis.NewClient(&redis.Options{Addr: fmt.Sprintf("localhost:%d", redisPort)}) - c.client = cache.NewRedisCache(redisClient, time.Hour, cache.RedisCompressionNone) + c.client = cache.NewRedisCache(redisClient, time.Hour, c.compression) }) if c.err != nil { return c.err @@ -72,6 +79,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) @@ -97,11 +110,13 @@ func (c *forwardCacheClient) NotifyUpdated(key string) error { } type forwardRepoClientset struct { - namespace string - context string - init sync.Once - repoClientset repoapiclient.Clientset - err error + namespace string + context string + init sync.Once + repoClientset repoapiclient.Clientset + err error + repoServerName string + kubeClientset kubernetes.Interface } func (c *forwardRepoClientset) NewRepoServerClient() (io.Closer, repoapiclient.RepoServerServiceClient, error) { @@ -109,7 +124,20 @@ func (c *forwardRepoClientset) NewRepoServerClient() (io.Closer, repoapiclient.R overrides := clientcmd.ConfigOverrides{ CurrentContext: c.context, } - repoServerPort, err := kubeutil.PortForward(8081, c.namespace, &overrides, "app.kubernetes.io/name=argocd-repo-server") + repoServerName := c.repoServerName + repoServererviceLabelSelector := common.LabelKeyComponentRepoServer + "=" + common.LabelValueComponentRepoServer + repoServerServices, err := c.kubeClientset.CoreV1().Services(c.namespace).List(context.Background(), v1.ListOptions{LabelSelector: repoServererviceLabelSelector}) + if err != nil { + c.err = err + return + } + if len(repoServerServices.Items) > 0 { + if repoServerServicelabel, ok := repoServerServices.Items[0].Labels[common.LabelKeyAppName]; ok && repoServerServicelabel != "" { + repoServerName = repoServerServicelabel + } + } + repoServerPodLabelSelector := common.LabelKeyAppName + "=" + repoServerName + repoServerPort, err := kubeutil.PortForward(8081, c.namespace, &overrides, repoServerPodLabelSelector) if err != nil { c.err = err return @@ -126,36 +154,47 @@ func (c *forwardRepoClientset) NewRepoServerClient() (io.Closer, repoapiclient.R func testAPI(ctx context.Context, clientOpts *apiclient.ClientOptions) error { apiClient, err := apiclient.NewClient(clientOpts) if err != nil { - return err + return fmt.Errorf("failed to create API client: %w", err) } closer, versionClient, err := apiClient.NewVersionClient() if err != nil { - return err + return fmt.Errorf("failed to create version client: %w", err) } defer io.Close(closer) _, err = versionClient.Version(ctx, &empty.Empty{}) - return err + if err != nil { + return fmt.Errorf("failed to get version: %w", err) + } + return nil } -// StartLocalServer allows executing command in a headless mode: on the fly starts Argo CD API server and -// changes provided client options to use started API server port -func StartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOptions, ctxStr string, port *int, address *string) error { - flags := pflag.NewFlagSet("tmp", pflag.ContinueOnError) - clientConfig := cli.AddKubectlFlagsToSet(flags) +// MaybeStartLocalServer allows executing command in a headless mode. If we're in core mode, starts the Argo CD API +// server on the fly and changes provided client options to use started API server port. +// +// 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, 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. localCfg, err := localconfig.ReadLocalConfig(clientOpts.ConfigPath) if err != nil { - return err + return fmt.Errorf("error reading local config: %w", err) } if localCfg != nil { configCtx, err := localCfg.ResolveContext(clientOpts.Context) if err != nil { - return err + return fmt.Errorf("error resolving context: %w", err) } + // There was a local config file, so determine whether core mode is enabled per the config file. startInProcessAPI = configCtx.Server.Core } } + // If we're in core mode, start the API server on the fly. if !startInProcessAPI { return nil } @@ -172,7 +211,7 @@ func StartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOptions, addr := fmt.Sprintf("%s:0", *address) ln, err := net.Listen("tcp", addr) if err != nil { - return err + return fmt.Errorf("failed to listen on %q: %w", addr, err) } port = &ln.Addr().(*net.TCPAddr).Port io.Close(ln) @@ -180,27 +219,27 @@ func StartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOptions, restConfig, err := clientConfig.ClientConfig() if err != nil { - return err + return fmt.Errorf("error creating client config: %w", err) } appClientset, err := appclientset.NewForConfig(restConfig) if err != nil { - return err + return fmt.Errorf("error creating app clientset: %w", err) } kubeClientset, err := kubernetes.NewForConfig(restConfig) if err != nil { - return err + return fmt.Errorf("error creating kubernetes clientset: %w", err) } namespace, _, err := clientConfig.Namespace() if err != nil { - return err + return fmt.Errorf("error getting namespace: %w", err) } mr, err := miniredis.Run() if err != nil { - return err + return fmt.Errorf("error running miniredis: %w", err) } - appstateCache := appstatecache.NewCache(cache.NewCache(&forwardCacheClient{namespace: namespace, context: ctxStr}), time.Hour) + appstateCache := appstatecache.NewCache(cache.NewCache(&forwardCacheClient{namespace: namespace, context: ctxStr, compression: compression, redisHaProxyName: clientOpts.RedisHaProxyName, redisName: clientOpts.RedisName}), time.Hour) srv := server.NewServer(ctx, server.ArgoCDServerOpts{ EnableGZip: false, Namespace: namespace, @@ -212,14 +251,14 @@ func StartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOptions, KubeClientset: kubeClientset, Insecure: true, ListenHost: *address, - RepoClientset: &forwardRepoClientset{namespace: namespace, context: ctxStr}, + RepoClientset: &forwardRepoClientset{namespace: namespace, context: ctxStr, repoServerName: clientOpts.RepoServerName, kubeClientset: kubeClientset}, EnableProxyExtension: false, }) srv.Init(ctx) lns, err := srv.Listen() if err != nil { - return err + return fmt.Errorf("failed to listen: %w", err) } go srv.Run(ctx, lns) clientOpts.ServerAddr = fmt.Sprintf("%s:%d", *address, *port) @@ -227,6 +266,7 @@ func StartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOptions, 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) @@ -235,7 +275,10 @@ func StartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOptions, } time.Sleep(time.Second) } - return err + if err != nil { + return fmt.Errorf("all retries failed: %w", err) + } + return nil } // NewClientOrDie creates a new API client from a set of config options, or fails fatally if the new client creation fails. @@ -243,7 +286,9 @@ func NewClientOrDie(opts *apiclient.ClientOptions, c *cobra.Command) apiclient.C ctx := c.Context() ctxStr := initialize.RetrieveContextIfChanged(c.Flag("context")) - err := StartLocalServer(ctx, opts, ctxStr, nil, nil) + // 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, nil) if err != nil { log.Fatal(err) } diff --git a/cmd/argocd/commands/initialize/cmd.go b/cmd/argocd/commands/initialize/cmd.go index 76a6470f07002..8f9da9f68783f 100644 --- a/cmd/argocd/commands/initialize/cmd.go +++ b/cmd/argocd/commands/initialize/cmd.go @@ -3,12 +3,11 @@ package initialize import ( "github.com/spf13/cobra" "github.com/spf13/pflag" - flag "github.com/spf13/pflag" "github.com/argoproj/argo-cd/v2/util/cli" ) -func RetrieveContextIfChanged(contextFlag *flag.Flag) string { +func RetrieveContextIfChanged(contextFlag *pflag.Flag) string { if contextFlag != nil && contextFlag.Changed { return contextFlag.Value.String() } diff --git a/cmd/argocd/commands/login.go b/cmd/argocd/commands/login.go index 2fc2ce3b32199..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 == "" { @@ -175,11 +176,11 @@ argocd login cd.argoproj.io --core`, fmt.Printf("Context '%s' updated\n", ctxName) }, } - command.Flags().StringVar(&ctxName, "name", "", "name to use for the context") - command.Flags().StringVar(&username, "username", "", "the username of an account to authenticate") - command.Flags().StringVar(&password, "password", "", "the password of an account to authenticate") - command.Flags().BoolVar(&sso, "sso", false, "perform SSO login") - command.Flags().IntVar(&ssoPort, "sso-port", DefaultSSOLocalPort, "port to run local OAuth2 login application") + command.Flags().StringVar(&ctxName, "name", "", "Name to use for the context") + command.Flags().StringVar(&username, "username", "", "The username of an account to authenticate") + command.Flags().StringVar(&password, "password", "", "The password of an account to authenticate") + command.Flags().BoolVar(&sso, "sso", false, "Perform SSO login") + command.Flags().IntVar(&ssoPort, "sso-port", DefaultSSOLocalPort, "Port to run local OAuth2 login application") command.Flags(). BoolVar(&skipTestTLS, "skip-test-tls", false, "Skip testing whether the server is configured with TLS (this can help when the command hangs for no apparent reason)") return command diff --git a/cmd/argocd/commands/login_test.go b/cmd/argocd/commands/login_test.go index 1f3289f97d563..3a7411b4b7fa3 100644 --- a/cmd/argocd/commands/login_test.go +++ b/cmd/argocd/commands/login_test.go @@ -7,8 +7,6 @@ import ( "github.com/stretchr/testify/assert" ) -// - func Test_userDisplayName_email(t *testing.T) { claims := jwt.MapClaims{"iss": "qux", "sub": "foo", "email": "firstname.lastname@example.com", "groups": []string{"baz"}} actualName := userDisplayName(claims) diff --git a/cmd/argocd/commands/logout.go b/cmd/argocd/commands/logout.go index e15450299347f..f64c57ccc89cc 100644 --- a/cmd/argocd/commands/logout.go +++ b/cmd/argocd/commands/logout.go @@ -18,6 +18,10 @@ func NewLogoutCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Comma Use: "logout CONTEXT", Short: "Log out from Argo CD", Long: "Log out from Argo CD", + Example: `# To log out of argocd +$ argocd logout +# This can be helpful for security reasons or when you want to switch between different Argo CD contexts or accounts. +`, Run: func(c *cobra.Command, args []string) { if len(args) == 0 { c.HelpFunc()(c, args) diff --git a/cmd/argocd/commands/project.go b/cmd/argocd/commands/project.go index be29249613f4c..be7517b843375 100644 --- a/cmd/argocd/commands/project.go +++ b/cmd/argocd/commands/project.go @@ -1,6 +1,7 @@ package commands import ( + "context" "encoding/json" "fmt" "io" @@ -10,11 +11,10 @@ import ( "time" humanize "github.com/dustin/go-humanize" - "github.com/ghodss/yaml" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/headless" cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" @@ -26,6 +26,7 @@ import ( "github.com/argoproj/argo-cd/v2/util/git" "github.com/argoproj/argo-cd/v2/util/gpg" argoio "github.com/argoproj/argo-cd/v2/util/io" + "github.com/argoproj/argo-cd/v2/util/templates" ) type policyOpts struct { @@ -39,6 +40,19 @@ func NewProjectCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ Use: "proj", Short: "Manage projects", + Example: templates.Examples(` + # List all available projects + argocd proj list + + # Create a new project with name PROJECT + argocd proj create PROJECT + + # Delete the project with name PROJECT + argocd proj delete PROJECT + + # Edit the information on project with name PROJECT + argocd proj edit PROJECT + `), Run: func(c *cobra.Command, args []string) { c.HelpFunc()(c, args) os.Exit(1) @@ -64,6 +78,8 @@ func NewProjectCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { command.AddCommand(NewProjectWindowsCommand(clientOpts)) command.AddCommand(NewProjectAddOrphanedIgnoreCommand(clientOpts)) command.AddCommand(NewProjectRemoveOrphanedIgnoreCommand(clientOpts)) + command.AddCommand(NewProjectAddSourceNamespace(clientOpts)) + command.AddCommand(NewProjectRemoveSourceNamespace(clientOpts)) return command } @@ -88,6 +104,13 @@ func NewProjectCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm var command = &cobra.Command{ Use: "create PROJECT", Short: "Create a project", + Example: templates.Examples(` + # 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 + argocd proj create PROJECT -f FILE|URL + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -118,6 +141,13 @@ func NewProjectSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command var command = &cobra.Command{ Use: "set PROJECT", Short: "Set project parameters", + Example: templates.Examples(` + # Set project parameters with some allowed cluster resources [RES1,RES2,...] for project with name PROJECT + argocd proj set PROJECT --allow-cluster-resource [RES1,RES2,...] + + # Set project parameters with some denied namespaced resources [RES1,RES2,...] for project with name PROJECT + argocd proj set PROJECT ---deny-namespaced-resource [RES1,RES2,...] + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -151,6 +181,10 @@ func NewProjectAddSignatureKeyCommand(clientOpts *argocdclient.ClientOptions) *c var command = &cobra.Command{ Use: "add-signature-key PROJECT KEY-ID", Short: "Add GnuPG signature key to project", + Example: templates.Examples(` + # Add GnuPG signature key KEY-ID to project PROJECT + argocd proj add-signature-key PROJECT KEY-ID + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -189,6 +223,10 @@ func NewProjectRemoveSignatureKeyCommand(clientOpts *argocdclient.ClientOptions) var command = &cobra.Command{ Use: "remove-signature-key PROJECT KEY-ID", Short: "Remove GnuPG signature key from project", + Example: templates.Examples(` + # Remove GnuPG signature key KEY-ID from project PROJECT + argocd proj remove-signature-key PROJECT KEY-ID + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -239,6 +277,13 @@ func NewProjectAddDestinationCommand(clientOpts *argocdclient.ClientOptions) *co var command = &cobra.Command{ Use: "add-destination PROJECT SERVER/NAME NAMESPACE", Short: "Add project destination", + Example: templates.Examples(` + # Add project destination using a server URL (SERVER) in the specified namespace (NAMESPACE) on the project with name PROJECT + argocd proj add-destination PROJECT SERVER NAMESPACE + + # Add project destination using a server name (NAME) in the specified namespace (NAMESPACE) on the project with name PROJECT + argocd proj add-destination PROJECT NAME NAMESPACE --name + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -276,6 +321,10 @@ func NewProjectRemoveDestinationCommand(clientOpts *argocdclient.ClientOptions) var command = &cobra.Command{ Use: "remove-destination PROJECT SERVER NAMESPACE", Short: "Remove project destination", + Example: templates.Examples(` + # Remove the destination (SERVER) from the specified namespace (NAMESPACE) on the project with name PROJECT + argocd proj remove-destination PROJECT SERVER NAMESPACE + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -320,6 +369,13 @@ func NewProjectAddOrphanedIgnoreCommand(clientOpts *argocdclient.ClientOptions) var command = &cobra.Command{ Use: "add-orphaned-ignore PROJECT GROUP KIND", Short: "Add a resource to orphaned ignore list", + Example: templates.Examples(` + # Add a resource of the specified GROUP and KIND to orphaned ignore list on the project with name PROJECT + argocd proj add-orphaned-ignore PROJECT GROUP KIND + + # Add resources of the specified GROUP and KIND using a NAME pattern to orphaned ignore list on the project with name PROJECT + argocd proj add-orphaned-ignore PROJECT GROUP KIND --name NAME + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -363,8 +419,15 @@ func NewProjectRemoveOrphanedIgnoreCommand(clientOpts *argocdclient.ClientOption name string ) var command = &cobra.Command{ - Use: "remove-orphaned-ignore PROJECT GROUP KIND NAME", + Use: "remove-orphaned-ignore PROJECT GROUP KIND", Short: "Remove a resource from orphaned ignore list", + Example: templates.Examples(` + # Remove a resource of the specified GROUP and KIND from orphaned ignore list on the project with name PROJECT + argocd proj remove-orphaned-ignore PROJECT GROUP KIND + + # Remove resources of the specified GROUP and KIND using a NAME pattern from orphaned ignore list on the project with name PROJECT + argocd proj remove-orphaned-ignore PROJECT GROUP KIND --name NAME + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -411,6 +474,10 @@ func NewProjectAddSourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.C var command = &cobra.Command{ Use: "add-source PROJECT URL", Short: "Add project source repository", + Example: templates.Examples(` + # Add a source repository (URL) to the project with name PROJECT + argocd proj add-source PROJECT URL + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -444,6 +511,88 @@ func NewProjectAddSourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.C return command } +// NewProjectAddSourceNamespace returns a new instance of an `argocd proj add-source-namespace` command +func NewProjectAddSourceNamespace(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var command = &cobra.Command{ + Use: "add-source-namespace PROJECT NAMESPACE", + Short: "Add source namespace to the AppProject", + Example: templates.Examples(` + # Add Kubernetes namespace as source namespace to the AppProject where application resources are allowed to be created in. + argocd proj add-source-namespace PROJECT NAMESPACE + `), + Run: func(c *cobra.Command, args []string) { + ctx := c.Context() + + if len(args) != 2 { + c.HelpFunc()(c, args) + os.Exit(1) + } + projName := args[0] + srcNamespace := args[1] + conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() + defer argoio.Close(conn) + + proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName}) + errors.CheckError(err) + + for _, item := range proj.Spec.SourceNamespaces { + if item == "*" || item == srcNamespace { + fmt.Printf("Source namespace '*' already allowed in project\n") + return + } + } + proj.Spec.SourceNamespaces = append(proj.Spec.SourceNamespaces, srcNamespace) + _, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj}) + errors.CheckError(err) + }, + } + return command +} + +// NewProjectRemoveSourceNamespace returns a new instance of an `argocd proj remove-source-namespace` command +func NewProjectRemoveSourceNamespace(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var command = &cobra.Command{ + Use: "remove-source-namespace PROJECT NAMESPACE", + Short: "Removes the source namespace from the AppProject", + Example: templates.Examples(` + # Remove source NAMESPACE in PROJECT + argocd proj remove-source-namespace PROJECT NAMESPACE + `), + Run: func(c *cobra.Command, args []string) { + ctx := c.Context() + + if len(args) != 2 { + c.HelpFunc()(c, args) + os.Exit(1) + } + projName := args[0] + srcNamespace := args[1] + conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() + defer argoio.Close(conn) + + proj, err := projIf.Get(ctx, &projectpkg.ProjectQuery{Name: projName}) + errors.CheckError(err) + + index := -1 + for i, item := range proj.Spec.SourceNamespaces { + if item == srcNamespace && item != "*" { + index = i + break + } + } + if index == -1 { + fmt.Printf("Source namespace '%s' does not exist in project or cannot be removed\n", srcNamespace) + } else { + proj.Spec.SourceNamespaces = append(proj.Spec.SourceNamespaces[:index], proj.Spec.SourceNamespaces[index+1:]...) + _, err = projIf.Update(ctx, &projectpkg.ProjectUpdateRequest{Project: proj}) + errors.CheckError(err) + } + }, + } + + return command +} + func modifyResourcesList(list *[]metav1.GroupKind, add bool, listDesc string, group string, kind string) bool { if add { for _, item := range *list { @@ -453,7 +602,7 @@ func modifyResourcesList(list *[]metav1.GroupKind, add bool, listDesc string, gr } } fmt.Printf("Group '%s' and kind '%s' is added to %s resources\n", group, kind, listDesc) - *list = append(*list, v1.GroupKind{Group: group, Kind: kind}) + *list = append(*list, metav1.GroupKind{Group: group, Kind: kind}) return true } else { index := -1 @@ -473,7 +622,7 @@ func modifyResourcesList(list *[]metav1.GroupKind, add bool, listDesc string, gr } } -func modifyResourceListCmd(cmdUse, cmdDesc string, clientOpts *argocdclient.ClientOptions, allow bool, namespacedList bool) *cobra.Command { +func modifyResourceListCmd(cmdUse, cmdDesc, examples string, clientOpts *argocdclient.ClientOptions, allow bool, namespacedList bool) *cobra.Command { var ( listType string defaultList string @@ -484,8 +633,9 @@ func modifyResourceListCmd(cmdUse, cmdDesc string, clientOpts *argocdclient.Clie defaultList = "allow" } var command = &cobra.Command{ - Use: cmdUse, - Short: cmdDesc, + Use: cmdUse, + Short: cmdDesc, + Example: templates.Examples(examples), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -534,28 +684,44 @@ func modifyResourceListCmd(cmdUse, cmdDesc string, clientOpts *argocdclient.Clie func NewProjectAllowNamespaceResourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { use := "allow-namespace-resource PROJECT GROUP KIND" desc := "Removes a namespaced API resource from the deny list or add a namespaced API resource to the allow list" - return modifyResourceListCmd(use, desc, clientOpts, true, true) + examples := ` + # Removes a namespaced API resource with specified GROUP and KIND from the deny list or add a namespaced API resource to the allow list for project PROJECT + argocd proj allow-namespace-resource PROJECT GROUP KIND + ` + return modifyResourceListCmd(use, desc, examples, clientOpts, true, true) } // NewProjectDenyNamespaceResourceCommand returns a new instance of an `argocd proj deny-namespace-resource` command func NewProjectDenyNamespaceResourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { use := "deny-namespace-resource PROJECT GROUP KIND" desc := "Adds a namespaced API resource to the deny list or removes a namespaced API resource from the allow list" - return modifyResourceListCmd(use, desc, clientOpts, false, true) + examples := ` + # Adds a namespaced API resource with specified GROUP and KIND from the deny list or removes a namespaced API resource from the allow list for project PROJECT + argocd proj deny-namespace-resource PROJECT GROUP KIND + ` + return modifyResourceListCmd(use, desc, examples, clientOpts, false, true) } // NewProjectDenyClusterResourceCommand returns a new instance of an `deny-cluster-resource` command func NewProjectDenyClusterResourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { use := "deny-cluster-resource PROJECT GROUP KIND" desc := "Removes a cluster-scoped API resource from the allow list and adds it to deny list" - return modifyResourceListCmd(use, desc, clientOpts, false, false) + examples := ` + # Removes a cluster-scoped API resource with specified GROUP and KIND from the allow list and adds it to deny list for project PROJECT + argocd proj deny-cluster-resource PROJECT GROUP KIND + ` + return modifyResourceListCmd(use, desc, examples, clientOpts, false, false) } // NewProjectAllowClusterResourceCommand returns a new instance of an `argocd proj allow-cluster-resource` command func NewProjectAllowClusterResourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { use := "allow-cluster-resource PROJECT GROUP KIND" desc := "Adds a cluster-scoped API resource to the allow list and removes it from deny list" - return modifyResourceListCmd(use, desc, clientOpts, true, false) + examples := ` + # Adds a cluster-scoped API resource with specified GROUP and KIND to the allow list and removes it from deny list for project PROJECT + argocd proj allow-cluster-resource PROJECT GROUP KIND + ` + return modifyResourceListCmd(use, desc, examples, clientOpts, true, false) } // NewProjectRemoveSourceCommand returns a new instance of an `argocd proj remove-src` command @@ -563,6 +729,10 @@ func NewProjectRemoveSourceCommand(clientOpts *argocdclient.ClientOptions) *cobr var command = &cobra.Command{ Use: "remove-source PROJECT URL", Short: "Remove project source repository", + Example: templates.Examples(` + # Remove URL source repository to project PROJECT + argocd proj remove-source PROJECT URL + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -603,6 +773,10 @@ func NewProjectDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm var command = &cobra.Command{ Use: "delete PROJECT", Short: "Delete project", + Example: templates.Examples(` + # Delete the project with name PROJECT + argocd proj delete PROJECT + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -646,6 +820,13 @@ func NewProjectListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comman var command = &cobra.Command{ Use: "list", Short: "List projects", + Example: templates.Examples(` + # List all available projects + argocd proj list + + # List all available projects in yaml format + argocd proj list -o yaml + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -811,6 +992,14 @@ func NewProjectGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command var command = &cobra.Command{ Use: "get PROJECT", Short: "Get project details", + Example: templates.Examples(` + # Get details from project PROJECT + argocd proj get PROJECT + + # Get details from project PROJECT in yaml format + argocd proj get PROJECT -o yaml + + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -819,10 +1008,7 @@ func NewProjectGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command os.Exit(1) } projName := args[0] - conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() - defer argoio.Close(conn) - detailedProject, err := projIf.GetDetailedProject(ctx, &projectpkg.ProjectQuery{Name: projName}) - errors.CheckError(err) + detailedProject := getProject(c, clientOpts, ctx, projName) switch output { case "yaml", "json": @@ -839,10 +1025,22 @@ func NewProjectGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command return command } +func getProject(c *cobra.Command, clientOpts *argocdclient.ClientOptions, ctx context.Context, projName string) *projectpkg.DetailedProjectsResponse { + conn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie() + defer argoio.Close(conn) + detailedProject, err := projIf.GetDetailedProject(ctx, &projectpkg.ProjectQuery{Name: projName}) + errors.CheckError(err) + return detailedProject +} + func NewProjectEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ Use: "edit PROJECT", Short: "Edit project", + Example: templates.Examples(` + # Edit the information on project with name PROJECT + argocd proj edit PROJECT + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() 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/relogin.go b/cmd/argocd/commands/relogin.go index b4c1ef7fe9b81..92affe05b2e5b 100644 --- a/cmd/argocd/commands/relogin.go +++ b/cmd/argocd/commands/relogin.go @@ -84,8 +84,20 @@ func NewReloginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Comm errors.CheckError(err) fmt.Printf("Context '%s' updated\n", localCfg.CurrentContext) }, + Example: ` +# Reinitiates the login with previous contexts +argocd relogin + +# Reinitiates the login with password +argocd relogin --password YOUR_PASSWORD + +# Configure direct access using Kubernetes API server +argocd login cd.argoproj.io --core + +# If user logged in with - "argocd login cd.argoproj.io" with sso login +# The command - "argocd relogin" will Reinitiates SSO login and updates the server context`, } - command.Flags().StringVar(&password, "password", "", "the password of an account to authenticate") - command.Flags().IntVar(&ssoPort, "sso-port", DefaultSSOLocalPort, "port to run local OAuth2 login application") + command.Flags().StringVar(&password, "password", "", "The password of an account to authenticate") + command.Flags().IntVar(&ssoPort, "sso-port", DefaultSSOLocalPort, "Port to run local OAuth2 login application") return command } diff --git a/cmd/argocd/commands/relogin_test.go b/cmd/argocd/commands/relogin_test.go new file mode 100644 index 0000000000000..eb6c4cd2d2f2d --- /dev/null +++ b/cmd/argocd/commands/relogin_test.go @@ -0,0 +1,64 @@ +package commands + +import ( + "strconv" + "testing" + + "github.com/stretchr/testify/assert" + + argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" +) + +func TestNewReloginCommand(t *testing.T) { + globalClientOpts := argocdclient.ClientOptions{ + ConfigPath: "/path/to/config", + } + + cmd := NewReloginCommand(&globalClientOpts) + + assert.Equal(t, "relogin", cmd.Use, "Unexpected command Use") + assert.Equal(t, "Refresh an expired authenticate token", cmd.Short, "Unexpected command Short") + assert.Equal(t, "Refresh an expired authenticate token", cmd.Long, "Unexpected command Long") + + // Assert command flags + passwordFlag := cmd.Flags().Lookup("password") + assert.NotNil(t, passwordFlag, "Expected flag --password to be defined") + assert.Equal(t, "", passwordFlag.Value.String(), "Unexpected default value for --password flag") + + ssoPortFlag := cmd.Flags().Lookup("sso-port") + port, err := strconv.Atoi(ssoPortFlag.Value.String()) + assert.NotNil(t, ssoPortFlag, "Expected flag --sso-port to be defined") + assert.NoError(t, err, "Failed to convert sso-port flag value to integer") + assert.Equal(t, 8085, port, "Unexpected default value for --sso-port flag") +} + +func TestNewReloginCommandWithGlobalClientOptions(t *testing.T) { + globalClientOpts := argocdclient.ClientOptions{ + ConfigPath: "/path/to/config", + ServerAddr: "https://argocd-server.example.com", + Insecure: true, + ClientCertFile: "/path/to/client-cert", + ClientCertKeyFile: "/path/to/client-cert-key", + GRPCWeb: true, + GRPCWebRootPath: "/path/to/grpc-web-root-path", + PlainText: true, + Headers: []string{"header1", "header2"}, + } + + cmd := NewReloginCommand(&globalClientOpts) + + assert.Equal(t, "relogin", cmd.Use, "Unexpected command Use") + assert.Equal(t, "Refresh an expired authenticate token", cmd.Short, "Unexpected command Short") + assert.Equal(t, "Refresh an expired authenticate token", cmd.Long, "Unexpected command Long") + + // Assert command flags + passwordFlag := cmd.Flags().Lookup("password") + assert.NotNil(t, passwordFlag, "Expected flag --password to be defined") + assert.Equal(t, "", passwordFlag.Value.String(), "Unexpected default value for --password flag") + + ssoPortFlag := cmd.Flags().Lookup("sso-port") + port, err := strconv.Atoi(ssoPortFlag.Value.String()) + assert.NotNil(t, ssoPortFlag, "Expected flag --sso-port to be defined") + assert.NoError(t, err, "Failed to convert sso-port flag value to integer") + assert.Equal(t, 8085, port, "Unexpected default value for --sso-port flag") +} diff --git a/cmd/argocd/commands/repo.go b/cmd/argocd/commands/repo.go index 1a540951c2231..1a5b4388fbeba 100644 --- a/cmd/argocd/commands/repo.go +++ b/cmd/argocd/commands/repo.go @@ -3,6 +3,7 @@ package commands import ( "fmt" "os" + "strconv" "text/tabwriter" log "github.com/sirupsen/logrus" @@ -28,6 +29,19 @@ func NewRepoCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { c.HelpFunc()(c, args) os.Exit(1) }, + Example: ` +# Add git repository connection parameters +argocd repo add git@git.example.com:repos/repo + +# Get a Configured Repository by URL +argocd repo get https://github.com/yourusername/your-repo.git + +# List Configured Repositories +argocd repo list + +# Remove Repository Credentials +argocd repo rm https://github.com/yourusername/your-repo.git +`, } command.AddCommand(NewRepoAddCommand(clientOpts)) @@ -50,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 @@ -160,6 +180,7 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { repoOpts.Repo.GithubAppInstallationId = repoOpts.GithubAppInstallationId repoOpts.Repo.GitHubAppEnterpriseBaseURL = repoOpts.GitHubAppEnterpriseBaseURL repoOpts.Repo.Proxy = repoOpts.Proxy + repoOpts.Repo.ForceHttpBasicAuth = repoOpts.ForceHttpBasicAuth if repoOpts.Repo.Type == "helm" && repoOpts.Repo.Name == "" { errors.CheckError(fmt.Errorf("Must specify --name for repos of type 'helm'")) @@ -199,6 +220,7 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { Proxy: repoOpts.Proxy, Project: repoOpts.Repo.Project, GcpServiceAccountKey: repoOpts.Repo.GCPServiceAccountKey, + ForceHttpBasicAuth: repoOpts.Repo.ForceHttpBasicAuth, } _, err := repoIf.ValidateAccess(ctx, &repoAccessReq) errors.CheckError(err) @@ -248,15 +270,12 @@ func printRepoTable(repos appsv1.Repositories) { _, _ = fmt.Fprintf(w, "TYPE\tNAME\tREPO\tINSECURE\tOCI\tLFS\tCREDS\tSTATUS\tMESSAGE\tPROJECT\n") for _, r := range repos { var hasCreds string - if !r.HasCredentials() { - hasCreds = "false" + if r.InheritedCreds { + hasCreds = "inherited" } else { - if r.InheritedCreds { - hasCreds = "inherited" - } else { - hasCreds = "true" - } + hasCreds = strconv.FormatBool(r.HasCredentials()) } + _, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%v\t%v\t%v\t%s\t%s\t%s\t%s\n", r.Type, r.Name, r.Repo, r.IsInsecure(), r.EnableOCI, r.EnableLFS, hasCreds, r.ConnectionState.Status, r.ConnectionState.Message, r.Project) } _ = w.Flush() @@ -309,7 +328,7 @@ func NewRepoListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { }, } command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|url") - command.Flags().StringVar(&refresh, "refresh", "", "Force a cache refresh on connection status") + command.Flags().StringVar(&refresh, "refresh", "", "Force a cache refresh on connection status , must be one of: 'hard'") return command } @@ -360,6 +379,6 @@ func NewRepoGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { }, } command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|url") - command.Flags().StringVar(&refresh, "refresh", "", "Force a cache refresh on connection status") + command.Flags().StringVar(&refresh, "refresh", "", "Force a cache refresh on connection status , must be one of: 'hard'") return command } diff --git a/cmd/argocd/commands/repocreds.go b/cmd/argocd/commands/repocreds.go index 43b2e6f191570..e43b9713a2927 100644 --- a/cmd/argocd/commands/repocreds.go +++ b/cmd/argocd/commands/repocreds.go @@ -17,6 +17,7 @@ import ( "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/git" "github.com/argoproj/argo-cd/v2/util/io" + "github.com/argoproj/argo-cd/v2/util/templates" ) // NewRepoCredsCommand returns a new instance of an `argocd repocreds` command @@ -24,6 +25,16 @@ func NewRepoCredsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command var command = &cobra.Command{ Use: "repocreds", Short: "Manage repository connection parameters", + Example: templates.Examples(` + # Add credentials with user/pass authentication to use for all repositories under the specified URL + argocd repocreds add URL --username USERNAME --password PASSWORD + + # List all the configured repository credentials + argocd repocreds list + + # Remove credentials for the repositories with speficied URL + argocd repocreds rm URL + `), Run: func(c *cobra.Command, args []string) { c.HelpFunc()(c, args) os.Exit(1) @@ -175,6 +186,7 @@ func NewRepoCredsAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma command.Flags().BoolVar(&repo.EnableOCI, "enable-oci", false, "Specifies whether helm-oci support should be enabled for this repo") command.Flags().StringVar(&repo.Type, "type", common.DefaultRepoType, "type of the repository, \"git\" or \"helm\"") command.Flags().StringVar(&gcpServiceAccountKeyPath, "gcp-service-account-key-path", "", "service account key for the Google Cloud Platform") + command.Flags().BoolVar(&repo.ForceHttpBasicAuth, "force-http-basic-auth", false, "whether to force basic auth when connecting via HTTP") return command } @@ -183,6 +195,10 @@ func NewRepoCredsRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co var command = &cobra.Command{ Use: "rm CREDSURL", Short: "Remove repository credentials", + Example: templates.Examples(` + # Remove credentials for the repositories with URL https://git.example.com/repos + argocd repocreds rm https://git.example.com/repos/ + `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -230,6 +246,19 @@ func NewRepoCredsListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm var command = &cobra.Command{ Use: "list", Short: "List configured repository credentials", + Example: templates.Examples(` + # List all repo urls + argocd repocreds list + + # 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/argocd/commands/root.go b/cmd/argocd/commands/root.go index 91ffde5997b3a..5c3b984e5bff5 100644 --- a/cmd/argocd/commands/root.go +++ b/cmd/argocd/commands/root.go @@ -1,15 +1,19 @@ package commands import ( + "fmt" + "github.com/spf13/cobra" "k8s.io/client-go/tools/clientcmd" "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/admin" "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/initialize" cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" + "github.com/argoproj/argo-cd/v2/common" argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" "github.com/argoproj/argo-cd/v2/util/cli" "github.com/argoproj/argo-cd/v2/util/config" + "github.com/argoproj/argo-cd/v2/util/env" "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/localconfig" ) @@ -55,7 +59,7 @@ func NewCommand() *cobra.Command { command.AddCommand(NewLogoutCommand(&clientOpts)) command.AddCommand(initialize.InitCommand(NewCertCommand(&clientOpts))) command.AddCommand(initialize.InitCommand(NewGPGCommand(&clientOpts))) - command.AddCommand(admin.NewAdminCommand()) + command.AddCommand(admin.NewAdminCommand(&clientOpts)) defaultLocalConfigPath, err := localconfig.DefaultLocalConfigPath() errors.CheckError(err) @@ -76,6 +80,11 @@ func NewCommand() *cobra.Command { command.PersistentFlags().StringVar(&clientOpts.PortForwardNamespace, "port-forward-namespace", config.GetFlag("port-forward-namespace", ""), "Namespace name which should be used for port forwarding") command.PersistentFlags().IntVar(&clientOpts.HttpRetryMax, "http-retry-max", 0, "Maximum number of retries to establish http connection to Argo CD server") command.PersistentFlags().BoolVar(&clientOpts.Core, "core", false, "If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server") + command.PersistentFlags().StringVar(&clientOpts.ServerName, "server-name", env.StringFromEnv(common.EnvServerName, common.DefaultServerName), fmt.Sprintf("Name of the Argo CD API server; set this or the %s environment variable when the server's name label differs from the default, for example when installing via the Helm chart", common.EnvServerName)) + command.PersistentFlags().StringVar(&clientOpts.AppControllerName, "controller-name", env.StringFromEnv(common.EnvAppControllerName, common.DefaultApplicationControllerName), fmt.Sprintf("Name of the Argo CD Application controller; set this or the %s environment variable when the controller's name label differs from the default, for example when installing via the Helm chart", common.EnvAppControllerName)) + command.PersistentFlags().StringVar(&clientOpts.RedisHaProxyName, "redis-haproxy-name", env.StringFromEnv(common.EnvRedisHaProxyName, common.DefaultRedisHaProxyName), fmt.Sprintf("Name of the Redis HA Proxy; set this or the %s environment variable when the HA Proxy's name label differs from the default, for example when installing via the Helm chart", common.EnvRedisHaProxyName)) + command.PersistentFlags().StringVar(&clientOpts.RedisName, "redis-name", env.StringFromEnv(common.EnvRedisName, common.DefaultRedisName), fmt.Sprintf("Name of the Redis deployment; set this or the %s environment variable when the Redis's name label differs from the default, for example when installing via the Helm chart", common.EnvRedisName)) + command.PersistentFlags().StringVar(&clientOpts.RepoServerName, "repo-server-name", env.StringFromEnv(common.EnvRepoServerName, common.DefaultRepoServerName), fmt.Sprintf("Name of the Argo CD Repo server; set this or the %s environment variable when the server's name label differs from the default, for example when installing via the Helm chart", common.EnvRepoServerName)) clientOpts.KubeOverrides = &clientcmd.ConfigOverrides{} command.PersistentFlags().StringVar(&clientOpts.KubeOverrides.CurrentContext, "kube-context", "", "Directs the command to the given kube-context") diff --git a/cmd/argocd/commands/tree.go b/cmd/argocd/commands/tree.go new file mode 100644 index 0000000000000..5261adb5b7f4a --- /dev/null +++ b/cmd/argocd/commands/tree.go @@ -0,0 +1,168 @@ +package commands + +import ( + "fmt" + "strings" + "text/tabwriter" + "time" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/gitops-engine/pkg/health" + "k8s.io/apimachinery/pkg/util/duration" +) + +const ( + firstElemPrefix = `├─` + lastElemPrefix = `└─` + indent = " " + pipe = `│ ` +) + +func extractHealthStatusAndReason(node v1alpha1.ResourceNode) (healthStatus health.HealthStatusCode, reason string) { + if node.Health != nil { + healthStatus = node.Health.Status + reason = node.Health.Message + } + return +} + +func treeViewAppGet(prefix string, uidToNodeMap map[string]v1alpha1.ResourceNode, parentToChildMap map[string][]string, parent v1alpha1.ResourceNode, mapNodeNameToResourceState map[string]*resourceState, w *tabwriter.Writer) { + healthStatus, _ := extractHealthStatusAndReason(parent) + if mapNodeNameToResourceState[parent.Kind+"/"+parent.Name] != nil { + value := mapNodeNameToResourceState[parent.Kind+"/"+parent.Name] + _, _ = fmt.Fprintf(w, "%s%s\t%s\t%s\t%s\n", printPrefix(prefix), parent.Kind+"/"+value.Name, value.Status, value.Health, value.Message) + } else { + _, _ = fmt.Fprintf(w, "%s%s\t%s\t%s\t%s\n", printPrefix(prefix), parent.Kind+"/"+parent.Name, "", healthStatus, "") + } + chs := parentToChildMap[parent.UID] + for i, childUid := range chs { + var p string + switch i { + case len(chs) - 1: + p = prefix + lastElemPrefix + default: + p = prefix + firstElemPrefix + } + treeViewAppGet(p, uidToNodeMap, parentToChildMap, uidToNodeMap[childUid], mapNodeNameToResourceState, w) + } + +} + +func detailedTreeViewAppGet(prefix string, uidToNodeMap map[string]v1alpha1.ResourceNode, parentChildMap map[string][]string, parent v1alpha1.ResourceNode, mapNodeNameToResourceState map[string]*resourceState, w *tabwriter.Writer) { + healthStatus, reason := extractHealthStatusAndReason(parent) + var age = "" + if parent.CreatedAt != nil { + age = duration.HumanDuration(time.Since(parent.CreatedAt.Time)) + } + + if mapNodeNameToResourceState[parent.Kind+"/"+parent.Name] != nil { + value := mapNodeNameToResourceState[parent.Kind+"/"+parent.Name] + _, _ = fmt.Fprintf(w, "%s%s\t%s\t%s\t%s\t%s\t%s\n", printPrefix(prefix), parent.Kind+"/"+value.Name, value.Status, value.Health, age, value.Message, reason) + } else { + _, _ = fmt.Fprintf(w, "%s%s\t%s\t%s\t%s\t%s\t%s\n", printPrefix(prefix), parent.Kind+"/"+parent.Name, "", healthStatus, age, "", reason) + + } + chs := parentChildMap[parent.UID] + for i, child := range chs { + var p string + switch i { + case len(chs) - 1: + p = prefix + lastElemPrefix + default: + p = prefix + firstElemPrefix + } + detailedTreeViewAppGet(p, uidToNodeMap, parentChildMap, uidToNodeMap[child], mapNodeNameToResourceState, w) + } +} + +func treeViewAppResourcesNotOrphaned(prefix string, uidToNodeMap map[string]v1alpha1.ResourceNode, parentChildMap map[string][]string, parent v1alpha1.ResourceNode, w *tabwriter.Writer) { + if len(parent.ParentRefs) == 0 { + _, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", parent.Group, parent.Kind, parent.Namespace, parent.Name, "No") + } + chs := parentChildMap[parent.UID] + for i, child := range chs { + var p string + switch i { + case len(chs) - 1: + p = prefix + lastElemPrefix + default: + p = prefix + firstElemPrefix + } + treeViewAppResourcesNotOrphaned(p, uidToNodeMap, parentChildMap, uidToNodeMap[child], w) + } +} + +func treeViewAppResourcesOrphaned(prefix string, uidToNodeMap map[string]v1alpha1.ResourceNode, parentChildMap map[string][]string, parent v1alpha1.ResourceNode, w *tabwriter.Writer) { + _, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", parent.Group, parent.Kind, parent.Namespace, parent.Name, "Yes") + chs := parentChildMap[parent.UID] + for i, child := range chs { + var p string + switch i { + case len(chs) - 1: + p = prefix + lastElemPrefix + default: + p = prefix + firstElemPrefix + } + treeViewAppResourcesOrphaned(p, uidToNodeMap, parentChildMap, uidToNodeMap[child], w) + } +} + +func detailedTreeViewAppResourcesNotOrphaned(prefix string, uidToNodeMap map[string]v1alpha1.ResourceNode, parentChildMap map[string][]string, parent v1alpha1.ResourceNode, w *tabwriter.Writer) { + + if len(parent.ParentRefs) == 0 { + healthStatus, reason := extractHealthStatusAndReason(parent) + var age = "" + if parent.CreatedAt != nil { + age = duration.HumanDuration(time.Since(parent.CreatedAt.Time)) + } + _, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", parent.Group, parent.Kind, parent.Namespace, parent.Name, "No", age, healthStatus, reason) + } + chs := parentChildMap[parent.UID] + for i, child := range chs { + var p string + switch i { + case len(chs) - 1: + p = prefix + lastElemPrefix + default: + p = prefix + firstElemPrefix + } + detailedTreeViewAppResourcesNotOrphaned(p, uidToNodeMap, parentChildMap, uidToNodeMap[child], w) + } +} + +func detailedTreeViewAppResourcesOrphaned(prefix string, uidToNodeMap map[string]v1alpha1.ResourceNode, parentChildMap map[string][]string, parent v1alpha1.ResourceNode, w *tabwriter.Writer) { + healthStatus, reason := extractHealthStatusAndReason(parent) + var age = "" + if parent.CreatedAt != nil { + age = duration.HumanDuration(time.Since(parent.CreatedAt.Time)) + } + _, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", parent.Group, parent.Kind, parent.Namespace, parent.Name, "Yes", age, healthStatus, reason) + + chs := parentChildMap[parent.UID] + for i, child := range chs { + var p string + switch i { + case len(chs) - 1: + p = prefix + lastElemPrefix + default: + p = prefix + firstElemPrefix + } + detailedTreeViewAppResourcesOrphaned(p, uidToNodeMap, parentChildMap, uidToNodeMap[child], w) + } +} + +func printPrefix(p string) string { + + if strings.HasSuffix(p, firstElemPrefix) { + p = strings.Replace(p, firstElemPrefix, pipe, strings.Count(p, firstElemPrefix)-1) + } else { + p = strings.ReplaceAll(p, firstElemPrefix, pipe) + } + + if strings.HasSuffix(p, lastElemPrefix) { + p = strings.Replace(p, lastElemPrefix, strings.Repeat(" ", len([]rune(lastElemPrefix))), strings.Count(p, lastElemPrefix)-1) + } else { + p = strings.ReplaceAll(p, lastElemPrefix, strings.Repeat(" ", len([]rune(lastElemPrefix)))) + } + return p +} diff --git a/cmd/argocd/commands/tree_test.go b/cmd/argocd/commands/tree_test.go new file mode 100644 index 0000000000000..91ffb9b963d01 --- /dev/null +++ b/cmd/argocd/commands/tree_test.go @@ -0,0 +1,216 @@ +package commands + +import ( + "bytes" + "testing" + "text/tabwriter" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/stretchr/testify/assert" +) + +func TestTreeViewAppGet(t *testing.T) { + var parent v1alpha1.ResourceNode + parent.ResourceRef = v1alpha1.ResourceRef{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"} + objs := make(map[string]v1alpha1.ResourceNode) + objs["87f3aab0-f634-4b2c-959a-7ddd30675ed0"] = parent + var child v1alpha1.ResourceNode + child.ResourceRef = v1alpha1.ResourceRef{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"} + child.ParentRefs = []v1alpha1.ResourceRef{{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"}} + + objs["75c30dce-1b66-414f-a86c-573a74be0f40"] = child + + childMapping := make(map[string][]string) + childMapping["87f3aab0-f634-4b2c-959a-7ddd30675ed0"] = []string{"75c30dce-1b66-414f-a86c-573a74be0f40"} + + stateMap := make(map[string]*resourceState) + stateMap["Rollout/numalogic-rollout-demo"] = &resourceState{ + Status: "Running", + Health: "Healthy", + Hook: "", + Message: "No Issues", + Name: "sandbox-rollout-numalogic-demo", + Kind: "Rollout", + Group: "argoproj.io", + } + + buf := &bytes.Buffer{} + w := tabwriter.NewWriter(buf, 0, 0, 2, ' ', 0) + treeViewAppGet("", objs, childMapping, parent, stateMap, w) + if err := w.Flush(); err != nil { + t.Fatal(err) + } + output := buf.String() + assert.Contains(t, output, "ReplicaSet") + assert.Contains(t, output, "Rollout") + assert.Contains(t, output, "numalogic-rollout") + assert.Contains(t, output, "Healthy") + assert.Contains(t, output, "No Issues") +} + +func TestTreeViewDetailedAppGet(t *testing.T) { + var parent v1alpha1.ResourceNode + parent.ResourceRef = v1alpha1.ResourceRef{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"} + objs := make(map[string]v1alpha1.ResourceNode) + objs["87f3aab0-f634-4b2c-959a-7ddd30675ed0"] = parent + var child v1alpha1.ResourceNode + child.ResourceRef = v1alpha1.ResourceRef{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"} + child.ParentRefs = []v1alpha1.ResourceRef{{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"}} + child.Health = &v1alpha1.HealthStatus{Status: "Degraded", Message: "Readiness Gate failed"} + objs["75c30dce-1b66-414f-a86c-573a74be0f40"] = child + + childMapping := make(map[string][]string) + childMapping["87f3aab0-f634-4b2c-959a-7ddd30675ed0"] = []string{"75c30dce-1b66-414f-a86c-573a74be0f40"} + + stateMap := make(map[string]*resourceState) + stateMap["Rollout/numalogic-rollout-demo"] = &resourceState{ + Status: "Running", + Health: "Healthy", + Hook: "", + Message: "No Issues", + Name: "sandbox-rollout-numalogic-demo", + Kind: "Rollout", + Group: "argoproj.io", + } + + buf := &bytes.Buffer{} + w := tabwriter.NewWriter(buf, 0, 0, 2, ' ', 0) + detailedTreeViewAppGet("", objs, childMapping, parent, stateMap, w) + if err := w.Flush(); err != nil { + t.Fatal(err) + } + + output := buf.String() + + assert.Contains(t, output, "ReplicaSet") + assert.Contains(t, output, "Rollout") + assert.Contains(t, output, "numalogic-rollout") + assert.Contains(t, output, "Healthy") + assert.Contains(t, output, "No Issues") + assert.Contains(t, output, "Degraded") + assert.Contains(t, output, "Readiness Gate failed") +} + +func TestTreeViewAppResources(t *testing.T) { + var parent v1alpha1.ResourceNode + parent.ResourceRef = v1alpha1.ResourceRef{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"} + objs := make(map[string]v1alpha1.ResourceNode) + objs["87f3aab0-f634-4b2c-959a-7ddd30675ed0"] = parent + var child v1alpha1.ResourceNode + child.ResourceRef = v1alpha1.ResourceRef{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"} + child.ParentRefs = []v1alpha1.ResourceRef{{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"}} + + objs["75c30dce-1b66-414f-a86c-573a74be0f40"] = child + + childMapping := make(map[string][]string) + childMapping["87f3aab0-f634-4b2c-959a-7ddd30675ed0"] = []string{"75c30dce-1b66-414f-a86c-573a74be0f40"} + + buf := &bytes.Buffer{} + w := tabwriter.NewWriter(buf, 0, 0, 2, ' ', 0) + + treeViewAppResourcesNotOrphaned("", objs, childMapping, parent, w) + + var orphan v1alpha1.ResourceNode + orphan.ResourceRef = v1alpha1.ResourceRef{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcdnk457d5", UID: "75c30dce-1b66-41hf-a86c-573a74be0f40"} + objsOrphan := make(map[string]v1alpha1.ResourceNode) + objsOrphan["75c30dce-1b66-41hf-a86c-573a74be0f40"] = orphan + orphanchildMapping := make(map[string][]string) + orphanParent := orphan + + treeViewAppResourcesOrphaned("", objsOrphan, orphanchildMapping, orphanParent, w) + if err := w.Flush(); err != nil { + t.Fatal(err) + } + output := buf.String() + + assert.Contains(t, output, "ReplicaSet") + assert.Contains(t, output, "Rollout") + assert.Contains(t, output, "numalogic-rollout") + assert.Contains(t, output, "argoproj.io") + assert.Contains(t, output, "No") + assert.Contains(t, output, "Yes") + assert.Contains(t, output, "numalogic-rollout-demo-5dcdnk457d5") +} + +func TestTreeViewDetailedAppResources(t *testing.T) { + var parent v1alpha1.ResourceNode + parent.ResourceRef = v1alpha1.ResourceRef{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"} + objs := make(map[string]v1alpha1.ResourceNode) + objs["87f3aab0-f634-4b2c-959a-7ddd30675ed0"] = parent + var child v1alpha1.ResourceNode + child.ResourceRef = v1alpha1.ResourceRef{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"} + child.ParentRefs = []v1alpha1.ResourceRef{{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"}} + objs["75c30dce-1b66-414f-a86c-573a74be0f40"] = child + childMapping := make(map[string][]string) + childMapping["87f3aab0-f634-4b2c-959a-7ddd30675ed0"] = []string{"75c30dce-1b66-414f-a86c-573a74be0f40"} + buf := &bytes.Buffer{} + w := tabwriter.NewWriter(buf, 0, 0, 2, ' ', 0) + detailedTreeViewAppResourcesNotOrphaned("", objs, childMapping, parent, w) + var orphan v1alpha1.ResourceNode + orphan.ResourceRef = v1alpha1.ResourceRef{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcdnk457d5", UID: "75c30dce-1b66-41hf-a86c-573a74be0f40"} + orphan.Health = &v1alpha1.HealthStatus{ + Status: "Degraded", + Message: "Readiness Gate failed", + } + objsOrphan := make(map[string]v1alpha1.ResourceNode) + objsOrphan["75c30dce-1b66-41hf-a86c-573a74be0f40"] = orphan + + orphanchildMapping := make(map[string][]string) + orphanParent := orphan + detailedTreeViewAppResourcesOrphaned("", objsOrphan, orphanchildMapping, orphanParent, w) + if err := w.Flush(); err != nil { + t.Fatal(err) + } + output := buf.String() + + assert.Contains(t, output, "ReplicaSet") + assert.Contains(t, output, "Rollout") + assert.Contains(t, output, "numalogic-rollout") + assert.Contains(t, output, "argoproj.io") + assert.Contains(t, output, "No") + assert.Contains(t, output, "Yes") + assert.Contains(t, output, "numalogic-rollout-demo-5dcdnk457d5") + assert.Contains(t, output, "Degraded") + assert.Contains(t, output, "Readiness Gate failed") +} + +func TestPrintPrefix(t *testing.T) { + tests := []struct { + input string + expected string + name string + }{ + { + input: "", + expected: "", + name: "empty string", + }, + { + input: firstElemPrefix, + expected: firstElemPrefix, + name: "only first element prefix", + }, + { + input: lastElemPrefix, + expected: lastElemPrefix, + name: "only last element prefix", + }, + { + input: firstElemPrefix + firstElemPrefix, + expected: pipe + firstElemPrefix, + name: "double first element prefix", + }, + { + input: firstElemPrefix + lastElemPrefix, + expected: pipe + lastElemPrefix, + name: "first then last element prefix", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := printPrefix(test.input) + assert.Equal(t, test.expected, got) + }) + } +} diff --git a/cmd/argocd/commands/version.go b/cmd/argocd/commands/version.go index 8f3d5b1abfe11..8c69c4195c3ad 100644 --- a/cmd/argocd/commands/version.go +++ b/cmd/argocd/commands/version.go @@ -116,6 +116,9 @@ func printClientVersion(version *common.Version, short bool) string { output += fmt.Sprintf(" GoVersion: %s\n", version.GoVersion) output += fmt.Sprintf(" Compiler: %s\n", version.Compiler) output += fmt.Sprintf(" Platform: %s\n", version.Platform) + if version.ExtraBuildInfo != "" { + output += fmt.Sprintf(" ExtraBuildInfo: %s\n", version.ExtraBuildInfo) + } return output } @@ -147,6 +150,9 @@ func printServerVersion(version *version.VersionMessage, short bool) string { if version.Platform != "" { output += fmt.Sprintf(" Platform: %s\n", version.Platform) } + if version.ExtraBuildInfo != "" { + output += fmt.Sprintf(" ExtraBuildInfo: %s\n", version.ExtraBuildInfo) + } if version.KustomizeVersion != "" { output += fmt.Sprintf(" Kustomize Version: %s\n", version.KustomizeVersion) } diff --git a/cmd/argocd/commands/version_test.go b/cmd/argocd/commands/version_test.go index 88aa689b48669..3312e5ad958b6 100644 --- a/cmd/argocd/commands/version_test.go +++ b/cmd/argocd/commands/version_test.go @@ -12,7 +12,7 @@ import ( func TestShortVersionClient(t *testing.T) { buf := new(bytes.Buffer) cmd := NewVersionCmd(&argocdclient.ClientOptions{}, nil) - cmd.SetOutput(buf) + cmd.SetOut(buf) cmd.SetArgs([]string{"version", "--short", "--client"}) err := cmd.Execute() if err != nil { @@ -26,7 +26,7 @@ func TestShortVersion(t *testing.T) { serverVersion := &version.VersionMessage{Version: "v99.99.99+unknown"} buf := new(bytes.Buffer) cmd := NewVersionCmd(&argocdclient.ClientOptions{}, serverVersion) - cmd.SetOutput(buf) + cmd.SetOut(buf) cmd.SetArgs([]string{"argocd", "version", "--short"}) err := cmd.Execute() if err != nil { diff --git a/cmd/util/app.go b/cmd/util/app.go index e80950533b054..b1693689004c4 100644 --- a/cmd/util/app.go +++ b/cmd/util/app.go @@ -64,11 +64,14 @@ type AppOptions struct { jsonnetExtVarCode []string jsonnetLibs []string kustomizeImages []string + kustomizeReplicas []string kustomizeVersion string kustomizeCommonLabels []string kustomizeCommonAnnotations []string + kustomizeLabelWithoutSelector bool kustomizeForceCommonLabels bool kustomizeForceCommonAnnotations bool + kustomizeNamespace string pluginEnvs []string Validate bool directoryExclude string @@ -77,6 +80,7 @@ type AppOptions struct { retryBackoffDuration time.Duration retryBackoffMaxDuration time.Duration retryBackoffFactor int64 + ref string } func AddAppFlags(command *cobra.Command, opts *AppOptions) { @@ -101,7 +105,7 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) { command.Flags().StringArrayVar(&opts.helmSetFiles, "helm-set-file", []string{}, "Helm set values from respective files specified via the command line (can be repeated to set several values: --helm-set-file key1=path1 --helm-set-file key2=path2)") command.Flags().BoolVar(&opts.helmSkipCrds, "helm-skip-crds", false, "Skip helm crd installation step") command.Flags().StringVar(&opts.project, "project", "", "Application project name") - command.Flags().StringVar(&opts.syncPolicy, "sync-policy", "", "Set the sync policy (one of: none, automated (aliases of automated: auto, automatic))") + command.Flags().StringVar(&opts.syncPolicy, "sync-policy", "", "Set the sync policy (one of: manual (aliases of manual: none), automated (aliases of automated: auto, automatic))") command.Flags().StringArrayVar(&opts.syncOptions, "sync-option", []string{}, "Add or remove a sync option, e.g add `Prune=false`. Remove using `!` prefix, e.g. `!Prune=false`") command.Flags().BoolVar(&opts.autoPrune, "auto-prune", false, "Set automatic pruning when sync is automated") command.Flags().BoolVar(&opts.selfHeal, "self-heal", false, "Set self healing when sync is automated") @@ -117,93 +121,52 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) { command.Flags().StringArrayVar(&opts.jsonnetExtVarCode, "jsonnet-ext-var-code", []string{}, "Jsonnet ext var") command.Flags().StringArrayVar(&opts.jsonnetLibs, "jsonnet-libs", []string{}, "Additional jsonnet libs (prefixed by repoRoot)") command.Flags().StringArrayVar(&opts.kustomizeImages, "kustomize-image", []string{}, "Kustomize images (e.g. --kustomize-image node:8.15.0 --kustomize-image mysql=mariadb,alpine@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d)") + command.Flags().StringArrayVar(&opts.kustomizeReplicas, "kustomize-replica", []string{}, "Kustomize replicas (e.g. --kustomize-replica my-development=2 --kustomize-replica my-statefulset=4)") command.Flags().StringArrayVar(&opts.pluginEnvs, "plugin-env", []string{}, "Additional plugin envs") command.Flags().BoolVar(&opts.Validate, "validate", true, "Validation of repo and cluster") command.Flags().StringArrayVar(&opts.kustomizeCommonLabels, "kustomize-common-label", []string{}, "Set common labels in Kustomize") command.Flags().StringArrayVar(&opts.kustomizeCommonAnnotations, "kustomize-common-annotation", []string{}, "Set common labels in Kustomize") + command.Flags().BoolVar(&opts.kustomizeLabelWithoutSelector, "kustomize-label-without-selector", false, "Do not apply common label to selectors or templates") command.Flags().BoolVar(&opts.kustomizeForceCommonLabels, "kustomize-force-common-label", false, "Force common labels in Kustomize") command.Flags().BoolVar(&opts.kustomizeForceCommonAnnotations, "kustomize-force-common-annotation", false, "Force common annotations in Kustomize") + command.Flags().StringVar(&opts.kustomizeNamespace, "kustomize-namespace", "", "Kustomize namespace") command.Flags().StringVar(&opts.directoryExclude, "directory-exclude", "", "Set glob expression used to exclude files from application source path") command.Flags().StringVar(&opts.directoryInclude, "directory-include", "", "Set glob expression used to include files from application source path") command.Flags().Int64Var(&opts.retryLimit, "sync-retry-limit", 0, "Max number of allowed sync retries") command.Flags().DurationVar(&opts.retryBackoffDuration, "sync-retry-backoff-duration", argoappv1.DefaultSyncRetryDuration, "Sync retry backoff base duration. Input needs to be a duration (e.g. 2m, 1h)") command.Flags().DurationVar(&opts.retryBackoffMaxDuration, "sync-retry-backoff-max-duration", argoappv1.DefaultSyncRetryMaxDuration, "Max sync retry backoff duration. Input needs to be a duration (e.g. 2m, 1h)") command.Flags().Int64Var(&opts.retryBackoffFactor, "sync-retry-backoff-factor", argoappv1.DefaultSyncRetryFactor, "Factor multiplies the base duration after each failed sync retry") + command.Flags().StringVar(&opts.ref, "ref", "", "Ref is reference to another source within sources field") } -func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, appOpts *AppOptions) int { +func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, appOpts *AppOptions, index int) int { visited := 0 if flags == nil { return visited } + source := spec.GetSourcePtr(index) + if source == nil { + source = &argoappv1.ApplicationSource{} + } + source, visited = ConstructSource(source, *appOpts, flags) + if spec.HasMultipleSources() { + if index == 0 { + spec.Sources[index] = *source + } else if index > 0 { + spec.Sources[index-1] = *source + } else { + spec.Sources = append(spec.Sources, *source) + } + } else { + spec.Source = source + } flags.Visit(func(f *pflag.Flag) { visited++ - source := spec.GetSourcePtr() - if source == nil { - source = &argoappv1.ApplicationSource{} - } + switch f.Name { - case "repo": - source.RepoURL = appOpts.repoURL - case "path": - source.Path = appOpts.appPath - case "helm-chart": - source.Chart = appOpts.chart - case "revision": - source.TargetRevision = appOpts.revision case "revision-history-limit": i := int64(appOpts.revisionHistoryLimit) spec.RevisionHistoryLimit = &i - case "values": - setHelmOpt(source, helmOpts{valueFiles: appOpts.valuesFiles}) - case "ignore-missing-value-files": - setHelmOpt(source, helmOpts{ignoreMissingValueFiles: appOpts.ignoreMissingValueFiles}) - case "values-literal-file": - var data []byte - - // read uri - parsedURL, err := url.ParseRequestURI(appOpts.values) - if err != nil || !(parsedURL.Scheme == "http" || parsedURL.Scheme == "https") { - data, err = os.ReadFile(appOpts.values) - } else { - data, err = config.ReadRemoteFile(appOpts.values) - } - errors.CheckError(err) - setHelmOpt(source, helmOpts{values: string(data)}) - case "release-name": - setHelmOpt(source, helmOpts{releaseName: appOpts.releaseName}) - case "helm-version": - setHelmOpt(source, helmOpts{version: appOpts.helmVersion}) - case "helm-pass-credentials": - setHelmOpt(source, helmOpts{passCredentials: appOpts.helmPassCredentials}) - case "helm-set": - setHelmOpt(source, helmOpts{helmSets: appOpts.helmSets}) - case "helm-set-string": - setHelmOpt(source, helmOpts{helmSetStrings: appOpts.helmSetStrings}) - case "helm-set-file": - setHelmOpt(source, helmOpts{helmSetFiles: appOpts.helmSetFiles}) - case "helm-skip-crds": - setHelmOpt(source, helmOpts{skipCrds: appOpts.helmSkipCrds}) - case "directory-recurse": - if source.Directory != nil { - source.Directory.Recurse = appOpts.directoryRecurse - } else { - source.Directory = &argoappv1.ApplicationSourceDirectory{Recurse: appOpts.directoryRecurse} - } - case "directory-exclude": - if source.Directory != nil { - source.Directory.Exclude = appOpts.directoryExclude - } else { - source.Directory = &argoappv1.ApplicationSourceDirectory{Exclude: appOpts.directoryExclude} - } - case "directory-include": - if source.Directory != nil { - source.Directory.Include = appOpts.directoryInclude - } else { - source.Directory = &argoappv1.ApplicationSourceDirectory{Include: appOpts.directoryInclude} - } - case "config-management-plugin": - source.Plugin = &argoappv1.ApplicationSourcePlugin{Name: appOpts.configManagementPlugin} case "dest-name": spec.Destination.Name = appOpts.destName case "dest-server": @@ -212,41 +175,9 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap spec.Destination.Namespace = appOpts.destNamespace case "project": spec.Project = appOpts.project - case "nameprefix": - setKustomizeOpt(source, kustomizeOpts{namePrefix: appOpts.namePrefix}) - case "namesuffix": - setKustomizeOpt(source, kustomizeOpts{nameSuffix: appOpts.nameSuffix}) - case "kustomize-image": - setKustomizeOpt(source, kustomizeOpts{images: appOpts.kustomizeImages}) - case "kustomize-version": - setKustomizeOpt(source, kustomizeOpts{version: appOpts.kustomizeVersion}) - case "kustomize-common-label": - parsedLabels, err := label.Parse(appOpts.kustomizeCommonLabels) - errors.CheckError(err) - setKustomizeOpt(source, kustomizeOpts{commonLabels: parsedLabels}) - case "kustomize-common-annotation": - parsedAnnotations, err := label.Parse(appOpts.kustomizeCommonAnnotations) - errors.CheckError(err) - setKustomizeOpt(source, kustomizeOpts{commonAnnotations: parsedAnnotations}) - case "kustomize-force-common-label": - setKustomizeOpt(source, kustomizeOpts{forceCommonLabels: appOpts.kustomizeForceCommonLabels}) - case "kustomize-force-common-annotation": - setKustomizeOpt(source, kustomizeOpts{forceCommonAnnotations: appOpts.kustomizeForceCommonAnnotations}) - case "jsonnet-tla-str": - setJsonnetOpt(source, appOpts.jsonnetTlaStr, false) - case "jsonnet-tla-code": - setJsonnetOpt(source, appOpts.jsonnetTlaCode, true) - case "jsonnet-ext-var-str": - setJsonnetOptExtVar(source, appOpts.jsonnetExtVarStr, false) - case "jsonnet-ext-var-code": - setJsonnetOptExtVar(source, appOpts.jsonnetExtVarCode, true) - case "jsonnet-libs": - setJsonnetOptLibs(source, appOpts.jsonnetLibs) - case "plugin-env": - setPluginOptEnvs(source, appOpts.pluginEnvs) case "sync-policy": switch appOpts.syncPolicy { - case "none": + case "none", "manual": if spec.SyncPolicy != nil { spec.SyncPolicy.Automated = nil } @@ -287,7 +218,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 { @@ -300,7 +231,6 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap log.Fatalf("Invalid sync-retry-limit [%d]", appOpts.retryLimit) } } - spec.Source = source }) if flags.Changed("auto-prune") { if spec.SyncPolicy == nil || spec.SyncPolicy.Automated == nil { @@ -328,11 +258,14 @@ type kustomizeOpts struct { namePrefix string nameSuffix string images []string + replicas []string version string commonLabels map[string]string commonAnnotations map[string]string + labelWithoutSelector bool forceCommonLabels bool forceCommonAnnotations bool + namespace string } func setKustomizeOpt(src *argoappv1.ApplicationSource, opts kustomizeOpts) { @@ -348,12 +281,18 @@ func setKustomizeOpt(src *argoappv1.ApplicationSource, opts kustomizeOpts) { if opts.nameSuffix != "" { src.Kustomize.NameSuffix = opts.nameSuffix } + if opts.namespace != "" { + src.Kustomize.Namespace = opts.namespace + } if opts.commonLabels != nil { src.Kustomize.CommonLabels = opts.commonLabels } if opts.commonAnnotations != nil { src.Kustomize.CommonAnnotations = opts.commonAnnotations } + if opts.labelWithoutSelector { + src.Kustomize.LabelWithoutSelector = opts.labelWithoutSelector + } if opts.forceCommonLabels { src.Kustomize.ForceCommonLabels = opts.forceCommonLabels } @@ -363,6 +302,14 @@ func setKustomizeOpt(src *argoappv1.ApplicationSource, opts kustomizeOpts) { for _, image := range opts.images { src.Kustomize.MergeImage(argoappv1.KustomizeImage(image)) } + for _, replica := range opts.replicas { + r, err := argoappv1.NewKustomizeReplica(replica) + if err != nil { + log.Fatal(err) + } + src.Kustomize.MergeReplica(*r) + } + if src.Kustomize.IsZero() { src.Kustomize = nil } @@ -406,7 +353,10 @@ func setHelmOpt(src *argoappv1.ApplicationSource, opts helmOpts) { src.Helm.IgnoreMissingValueFiles = opts.ignoreMissingValueFiles } if len(opts.values) > 0 { - src.Helm.Values = opts.values + err := src.Helm.SetValuesString(opts.values) + if err != nil { + log.Fatal(err) + } } if opts.releaseName != "" { src.Helm.ReleaseName = opts.releaseName @@ -474,11 +424,11 @@ func setJsonnetOptLibs(src *argoappv1.ApplicationSource, libs []string) { // SetParameterOverrides updates an existing or appends a new parameter override in the application // The app is assumed to be a helm app and is expected to be in the form: // param=value -func SetParameterOverrides(app *argoappv1.Application, parameters []string) { +func SetParameterOverrides(app *argoappv1.Application, parameters []string, index int) { if len(parameters) == 0 { return } - source := app.Spec.GetSource() + source := app.Spec.GetSourcePtr(index) var sourceType argoappv1.ApplicationSourceType if st, _ := source.ExplicitType(); st != nil { sourceType = *st @@ -576,7 +526,7 @@ func constructAppsBaseOnName(appName string, labels, annotations, args []string, } appName = args[0] } - appName, appNs := argo.ParseAppQualifiedName(appName, "") + appName, appNs := argo.ParseFromQualifiedName(appName, "") app = &argoappv1.Application{ TypeMeta: v1.TypeMeta{ Kind: application.ApplicationKind, @@ -590,8 +540,8 @@ func constructAppsBaseOnName(appName string, labels, annotations, args []string, Source: &argoappv1.ApplicationSource{}, }, } - SetAppSpecOptions(flags, &app.Spec, &appOpts) - SetParameterOverrides(app, appOpts.Parameters) + SetAppSpecOptions(flags, &app.Spec, &appOpts, 0) + SetParameterOverrides(app, appOpts.Parameters, 0) mergeLabels(app, labels) setAnnotations(app, annotations) return []*argoappv1.Application{ @@ -616,10 +566,15 @@ func constructAppsFromFileUrl(fileURL, appName string, labels, annotations, args if app.Name == "" { return nil, fmt.Errorf("app.Name is empty. --name argument can be used to provide app.Name") } - SetAppSpecOptions(flags, &app.Spec, &appOpts) - SetParameterOverrides(app, appOpts.Parameters) + mergeLabels(app, labels) setAnnotations(app, annotations) + + // do not allow overrides for applications with multiple sources + if !app.Spec.HasMultipleSources() { + SetAppSpecOptions(flags, &app.Spec, &appOpts, 0) + SetParameterOverrides(app, appOpts.Parameters, 0) + } } return apps, nil } @@ -630,9 +585,117 @@ func ConstructApps(fileURL, appName string, labels, annotations, args []string, } else if fileURL != "" { return constructAppsFromFileUrl(fileURL, appName, labels, annotations, args, appOpts, flags) } + return constructAppsBaseOnName(appName, labels, annotations, args, appOpts, flags) } +func ConstructSource(source *argoappv1.ApplicationSource, appOpts AppOptions, flags *pflag.FlagSet) (*argoappv1.ApplicationSource, int) { + visited := 0 + flags.Visit(func(f *pflag.Flag) { + visited++ + switch f.Name { + case "repo": + source.RepoURL = appOpts.repoURL + case "path": + source.Path = appOpts.appPath + case "helm-chart": + source.Chart = appOpts.chart + case "revision": + source.TargetRevision = appOpts.revision + case "values": + setHelmOpt(source, helmOpts{valueFiles: appOpts.valuesFiles}) + case "ignore-missing-value-files": + setHelmOpt(source, helmOpts{ignoreMissingValueFiles: appOpts.ignoreMissingValueFiles}) + case "values-literal-file": + var data []byte + // read uri + parsedURL, err := url.ParseRequestURI(appOpts.values) + if err != nil || !(parsedURL.Scheme == "http" || parsedURL.Scheme == "https") { + data, err = os.ReadFile(appOpts.values) + } else { + data, err = config.ReadRemoteFile(appOpts.values) + } + errors.CheckError(err) + setHelmOpt(source, helmOpts{values: string(data)}) + case "release-name": + setHelmOpt(source, helmOpts{releaseName: appOpts.releaseName}) + case "helm-version": + setHelmOpt(source, helmOpts{version: appOpts.helmVersion}) + case "helm-pass-credentials": + setHelmOpt(source, helmOpts{passCredentials: appOpts.helmPassCredentials}) + case "helm-set": + setHelmOpt(source, helmOpts{helmSets: appOpts.helmSets}) + case "helm-set-string": + setHelmOpt(source, helmOpts{helmSetStrings: appOpts.helmSetStrings}) + case "helm-set-file": + setHelmOpt(source, helmOpts{helmSetFiles: appOpts.helmSetFiles}) + case "helm-skip-crds": + setHelmOpt(source, helmOpts{skipCrds: appOpts.helmSkipCrds}) + case "directory-recurse": + if source.Directory != nil { + source.Directory.Recurse = appOpts.directoryRecurse + } else { + source.Directory = &argoappv1.ApplicationSourceDirectory{Recurse: appOpts.directoryRecurse} + } + case "directory-exclude": + if source.Directory != nil { + source.Directory.Exclude = appOpts.directoryExclude + } else { + source.Directory = &argoappv1.ApplicationSourceDirectory{Exclude: appOpts.directoryExclude} + } + case "directory-include": + if source.Directory != nil { + source.Directory.Include = appOpts.directoryInclude + } else { + source.Directory = &argoappv1.ApplicationSourceDirectory{Include: appOpts.directoryInclude} + } + case "config-management-plugin": + source.Plugin = &argoappv1.ApplicationSourcePlugin{Name: appOpts.configManagementPlugin} + case "nameprefix": + setKustomizeOpt(source, kustomizeOpts{namePrefix: appOpts.namePrefix}) + case "namesuffix": + setKustomizeOpt(source, kustomizeOpts{nameSuffix: appOpts.nameSuffix}) + case "kustomize-image": + setKustomizeOpt(source, kustomizeOpts{images: appOpts.kustomizeImages}) + case "kustomize-replica": + setKustomizeOpt(source, kustomizeOpts{replicas: appOpts.kustomizeReplicas}) + case "kustomize-version": + setKustomizeOpt(source, kustomizeOpts{version: appOpts.kustomizeVersion}) + case "kustomize-namespace": + setKustomizeOpt(source, kustomizeOpts{namespace: appOpts.kustomizeNamespace}) + case "kustomize-common-label": + parsedLabels, err := label.Parse(appOpts.kustomizeCommonLabels) + errors.CheckError(err) + setKustomizeOpt(source, kustomizeOpts{commonLabels: parsedLabels}) + case "kustomize-common-annotation": + parsedAnnotations, err := label.Parse(appOpts.kustomizeCommonAnnotations) + errors.CheckError(err) + setKustomizeOpt(source, kustomizeOpts{commonAnnotations: parsedAnnotations}) + case "kustomize-label-without-selector": + setKustomizeOpt(source, kustomizeOpts{labelWithoutSelector: appOpts.kustomizeLabelWithoutSelector}) + case "kustomize-force-common-label": + setKustomizeOpt(source, kustomizeOpts{forceCommonLabels: appOpts.kustomizeForceCommonLabels}) + case "kustomize-force-common-annotation": + setKustomizeOpt(source, kustomizeOpts{forceCommonAnnotations: appOpts.kustomizeForceCommonAnnotations}) + case "jsonnet-tla-str": + setJsonnetOpt(source, appOpts.jsonnetTlaStr, false) + case "jsonnet-tla-code": + setJsonnetOpt(source, appOpts.jsonnetTlaCode, true) + case "jsonnet-ext-var-str": + setJsonnetOptExtVar(source, appOpts.jsonnetExtVarStr, false) + case "jsonnet-ext-var-code": + setJsonnetOptExtVar(source, appOpts.jsonnetExtVarCode, true) + case "jsonnet-libs": + setJsonnetOptLibs(source, appOpts.jsonnetLibs) + case "plugin-env": + setPluginOptEnvs(source, appOpts.pluginEnvs) + case "ref": + source.Ref = appOpts.ref + } + }) + return source, visited +} + func mergeLabels(app *argoappv1.Application, labels []string) { mapLabels, err := label.Parse(labels) errors.CheckError(err) @@ -664,7 +727,7 @@ func setAnnotations(app *argoappv1.Application, annotations []string) { } } -// liveObjects deserializes the list of live states into unstructured objects +// LiveObjects deserializes the list of live states into unstructured objects func LiveObjects(resources []*argoappv1.ResourceDiff) ([]*unstructured.Unstructured, error) { objs := make([]*unstructured.Unstructured, len(resources)) for i, resState := range resources { diff --git a/cmd/util/app_test.go b/cmd/util/app_test.go index 2e8ddc9e0fee7..5e95eeb388634 100644 --- a/cmd/util/app_test.go +++ b/cmd/util/app_test.go @@ -9,7 +9,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + + "k8s.io/apimachinery/pkg/util/intstr" ) func Test_setHelmOpt(t *testing.T) { @@ -86,11 +87,32 @@ func Test_setKustomizeOpt(t *testing.T) { setKustomizeOpt(&src, kustomizeOpts{images: []string{"org/image:v1", "org/image:v2"}}) assert.Equal(t, &v1alpha1.ApplicationSourceKustomize{Images: v1alpha1.KustomizeImages{v1alpha1.KustomizeImage("org/image:v2")}}, src.Kustomize) }) + t.Run("Replicas", func(t *testing.T) { + src := v1alpha1.ApplicationSource{} + testReplicasString := []string{"my-deployment=2", "my-statefulset=4"} + testReplicas := v1alpha1.KustomizeReplicas{ + { + Name: "my-deployment", + Count: intstr.FromInt(2), + }, + { + Name: "my-statefulset", + Count: intstr.FromInt(4), + }, + } + setKustomizeOpt(&src, kustomizeOpts{replicas: testReplicasString}) + assert.Equal(t, &v1alpha1.ApplicationSourceKustomize{Replicas: testReplicas}, src.Kustomize) + }) t.Run("Version", func(t *testing.T) { src := v1alpha1.ApplicationSource{} setKustomizeOpt(&src, kustomizeOpts{version: "v0.1"}) assert.Equal(t, &v1alpha1.ApplicationSourceKustomize{Version: "v0.1"}, src.Kustomize) }) + t.Run("Namespace", func(t *testing.T) { + src := v1alpha1.ApplicationSource{} + setKustomizeOpt(&src, kustomizeOpts{namespace: "custom-namespace"}) + assert.Equal(t, &v1alpha1.ApplicationSourceKustomize{Namespace: "custom-namespace"}, src.Kustomize) + }) t.Run("Common labels", func(t *testing.T) { src := v1alpha1.ApplicationSource{} setKustomizeOpt(&src, kustomizeOpts{commonLabels: map[string]string{"foo1": "bar1", "foo2": "bar2"}}) @@ -101,6 +123,11 @@ func Test_setKustomizeOpt(t *testing.T) { setKustomizeOpt(&src, kustomizeOpts{commonAnnotations: map[string]string{"foo1": "bar1", "foo2": "bar2"}}) assert.Equal(t, &v1alpha1.ApplicationSourceKustomize{CommonAnnotations: map[string]string{"foo1": "bar1", "foo2": "bar2"}}, src.Kustomize) }) + t.Run("Label Without Selector", func(t *testing.T) { + src := v1alpha1.ApplicationSource{} + setKustomizeOpt(&src, kustomizeOpts{commonLabels: map[string]string{"foo1": "bar1", "foo2": "bar2"}, labelWithoutSelector: true}) + assert.Equal(t, &v1alpha1.ApplicationSourceKustomize{CommonLabels: map[string]string{"foo1": "bar1", "foo2": "bar2"}, LabelWithoutSelector: true}, src.Kustomize) + }) } func Test_setJsonnetOpt(t *testing.T) { @@ -143,7 +170,16 @@ func (f *appOptionsFixture) SetFlag(key, value string) error { if err != nil { return err } - _ = SetAppSpecOptions(f.command.Flags(), f.spec, f.options) + _ = SetAppSpecOptions(f.command.Flags(), f.spec, f.options, 0) + return err +} + +func (f *appOptionsFixture) SetFlagWithSourceIndex(key, value string, index int) error { + err := f.command.Flags().Set(key, value) + if err != nil { + return err + } + _ = SetAppSpecOptions(f.command.Flags(), f.spec, f.options, index) return err } @@ -191,6 +227,59 @@ func Test_setAppSpecOptions(t *testing.T) { assert.NoError(t, f.SetFlag("sync-retry-limit", "0")) assert.Nil(t, f.spec.SyncPolicy.Retry) }) + t.Run("Kustomize", func(t *testing.T) { + assert.NoError(t, f.SetFlag("kustomize-replica", "my-deployment=2")) + assert.NoError(t, f.SetFlag("kustomize-replica", "my-statefulset=4")) + assert.Equal(t, f.spec.Source.Kustomize.Replicas, v1alpha1.KustomizeReplicas{{Name: "my-deployment", Count: intstr.FromInt(2)}, {Name: "my-statefulset", Count: intstr.FromInt(4)}}) + }) +} + +func newMultiSourceAppOptionsFixture() *appOptionsFixture { + fixture := &appOptionsFixture{ + spec: &v1alpha1.ApplicationSpec{ + Sources: v1alpha1.ApplicationSources{ + v1alpha1.ApplicationSource{}, + v1alpha1.ApplicationSource{}, + }, + }, + command: &cobra.Command{}, + options: &AppOptions{}, + } + AddAppFlags(fixture.command, fixture.options) + return fixture +} + +func Test_setAppSpecOptionsMultiSourceApp(t *testing.T) { + f := newMultiSourceAppOptionsFixture() + index := 0 + index1 := 1 + index2 := 2 + t.Run("SyncPolicy", func(t *testing.T) { + assert.NoError(t, f.SetFlagWithSourceIndex("sync-policy", "automated", index1)) + assert.NotNil(t, f.spec.SyncPolicy.Automated) + + f.spec.SyncPolicy = nil + assert.NoError(t, f.SetFlagWithSourceIndex("sync-policy", "automatic", index1)) + assert.NotNil(t, f.spec.SyncPolicy.Automated) + }) + t.Run("Helm - Index 0", func(t *testing.T) { + assert.NoError(t, f.SetFlagWithSourceIndex("helm-version", "v2", index)) + assert.Equal(t, len(f.spec.GetSources()), 2) + assert.Equal(t, f.spec.GetSources()[index].Helm.Version, "v2") + }) + t.Run("Kustomize", func(t *testing.T) { + assert.NoError(t, f.SetFlagWithSourceIndex("kustomize-replica", "my-deployment=2", index1)) + assert.Equal(t, f.spec.Sources[index1-1].Kustomize.Replicas, v1alpha1.KustomizeReplicas{{Name: "my-deployment", Count: intstr.FromInt(2)}}) + assert.NoError(t, f.SetFlagWithSourceIndex("kustomize-replica", "my-deployment=4", index2)) + assert.Equal(t, f.spec.Sources[index2-1].Kustomize.Replicas, v1alpha1.KustomizeReplicas{{Name: "my-deployment", Count: intstr.FromInt(4)}}) + }) + t.Run("Helm", func(t *testing.T) { + assert.NoError(t, f.SetFlagWithSourceIndex("helm-version", "v2", index1)) + assert.NoError(t, f.SetFlagWithSourceIndex("helm-version", "v3", index2)) + assert.Equal(t, len(f.spec.GetSources()), 2) + assert.Equal(t, f.spec.GetSources()[index1-1].Helm.Version, "v2") + assert.Equal(t, f.spec.GetSources()[index2-1].Helm.Version, "v3") + }) } func Test_setAnnotations(t *testing.T) { @@ -266,7 +355,7 @@ func TestReadAppsFromURI(t *testing.T) { _, _ = file.WriteString(appsYaml) _ = file.Sync() - apps := make([]*argoappv1.Application, 0) + apps := make([]*v1alpha1.Application, 0) err = readAppsFromURI(file.Name(), &apps) assert.NoError(t, err) assert.Equal(t, 2, len(apps)) diff --git a/cmd/util/applicationset.go b/cmd/util/applicationset.go index 97e40cedcdac2..2b096aa6aa036 100644 --- a/cmd/util/applicationset.go +++ b/cmd/util/applicationset.go @@ -61,6 +61,6 @@ func readAppset(yml []byte, appsets *[]*argoprojiov1alpha1.ApplicationSet) error *appsets = append(*appsets, &appset) } - - return fmt.Errorf("error reading app set: %w", err) + // we reach here if there is no error found while reading the Application Set + return nil } diff --git a/cmd/util/applicationset_test.go b/cmd/util/applicationset_test.go index 78c07f7e0d005..c15e58a61af14 100644 --- a/cmd/util/applicationset_test.go +++ b/cmd/util/applicationset_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" ) -var appSet string = `apiVersion: argoproj.io/v1alpha1 +var appSet = `apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: name: guestbook @@ -31,10 +31,10 @@ spec: ` func TestReadAppSet(t *testing.T) { - appsets := []*argoprojiov1alpha1.ApplicationSet{} - err := readAppset([]byte(appSet), &appsets) + var appSets []*argoprojiov1alpha1.ApplicationSet + err := readAppset([]byte(appSet), &appSets) if err != nil { t.Logf("Failed reading appset file") } - assert.Equal(t, len(appsets), 1) + assert.Equal(t, len(appSets), 1) } diff --git a/cmd/util/cluster.go b/cmd/util/cluster.go index 1da0e53709993..dffb52e775a97 100644 --- a/cmd/util/cluster.go +++ b/cmd/util/cluster.go @@ -1,6 +1,7 @@ package util import ( + "context" "fmt" "os" "sort" @@ -8,13 +9,25 @@ import ( "text/tabwriter" "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + clientcmdapiv1 "k8s.io/client-go/tools/clientcmd/api/v1" + "sigs.k8s.io/yaml" argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/util/errors" ) +type ClusterEndpoint string + +const ( + KubeConfigEndpoint ClusterEndpoint = "kubeconfig" + KubePublicEndpoint ClusterEndpoint = "kube-public" + KubeInternalEndpoint ClusterEndpoint = "internal" +) + func PrintKubeContexts(ca clientcmd.ConfigAccess) { config, err := ca.GetStartingConfig() errors.CheckError(err) @@ -102,11 +115,36 @@ func NewCluster(name string, namespaces []string, clusterResources bool, conf *r return &clst } +// GetKubePublicEndpoint returns the kubernetes apiserver endpoint as published +// in the kube-public. +func GetKubePublicEndpoint(client kubernetes.Interface) (string, error) { + clusterInfo, err := client.CoreV1().ConfigMaps("kube-public").Get(context.TODO(), "cluster-info", metav1.GetOptions{}) + if err != nil { + return "", err + } + kubeconfig, ok := clusterInfo.Data["kubeconfig"] + if !ok { + return "", fmt.Errorf("cluster-info does not contain a public kubeconfig") + } + // Parse Kubeconfig and get server address + config := &clientcmdapiv1.Config{} + err = yaml.Unmarshal([]byte(kubeconfig), config) + if err != nil { + return "", fmt.Errorf("failed to parse cluster-info kubeconfig: %v", err) + } + if len(config.Clusters) == 0 { + return "", fmt.Errorf("cluster-info kubeconfig does not have any clusters") + } + + return config.Clusters[0].Cluster.Server, nil +} + type ClusterOptions struct { InCluster bool Upsert bool ServiceAccount string AwsRoleArn string + AwsProfile string AwsClusterName string SystemNamespace string Namespaces []string @@ -119,12 +157,20 @@ type ClusterOptions struct { ExecProviderEnv map[string]string ExecProviderAPIVersion string ExecProviderInstallHint string + ClusterEndpoint string +} + +// InClusterEndpoint returns true if ArgoCD should reference the in-cluster +// endpoint when registering the target cluster. +func (o ClusterOptions) InClusterEndpoint() bool { + return o.InCluster || o.ClusterEndpoint == string(KubeInternalEndpoint) } 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") @@ -135,4 +181,5 @@ func AddClusterFlags(command *cobra.Command, opts *ClusterOptions) { command.Flags().StringToStringVar(&opts.ExecProviderEnv, "exec-command-env", nil, "Environment vars to set when running the --exec-command executable") command.Flags().StringVar(&opts.ExecProviderAPIVersion, "exec-command-api-version", "", "Preferred input version of the ExecInfo for the --exec-command executable") command.Flags().StringVar(&opts.ExecProviderInstallHint, "exec-command-install-hint", "", "Text shown to the user when the --exec-command executable doesn't seem to be present") + command.Flags().StringVar(&opts.ClusterEndpoint, "cluster-endpoint", "", "Cluster endpoint to use. Can be one of the following: 'kubeconfig', 'kube-public', or 'internal'.") } diff --git a/cmd/util/cluster_test.go b/cmd/util/cluster_test.go index 6afea6fa7c17c..37e05bf6e58cb 100644 --- a/cmd/util/cluster_test.go +++ b/cmd/util/cluster_test.go @@ -5,7 +5,13 @@ import ( "testing" "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/rest" + clientcmdapiv1 "k8s.io/client-go/tools/clientcmd/api/v1" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) @@ -69,3 +75,109 @@ func Test_newCluster(t *testing.T) { assert.Nil(t, clusterWithBearerToken.Labels) assert.Nil(t, clusterWithBearerToken.Annotations) } + +func TestGetKubePublicEndpoint(t *testing.T) { + cases := []struct { + name string + clusterInfo *corev1.ConfigMap + expectedEndpoint string + expectError bool + }{ + { + name: "has public endpoint", + clusterInfo: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "kube-public", + Name: "cluster-info", + }, + Data: map[string]string{ + "kubeconfig": kubeconfigFixture("https://test-cluster:6443"), + }, + }, + expectedEndpoint: "https://test-cluster:6443", + }, + { + name: "no cluster-info", + expectError: true, + }, + { + name: "no kubeconfig in cluster-info", + clusterInfo: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "kube-public", + Name: "cluster-info", + }, + Data: map[string]string{ + "argo": "the project, not the movie", + }, + }, + expectError: true, + }, + { + name: "no clusters in cluster-info kubeconfig", + clusterInfo: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "kube-public", + Name: "cluster-info", + }, + Data: map[string]string{ + "kubeconfig": kubeconfigFixture(""), + }, + }, + expectError: true, + }, + { + name: "can't parse kubeconfig", + clusterInfo: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "kube-public", + Name: "cluster-info", + }, + Data: map[string]string{ + "kubeconfig": "this is not valid YAML", + }, + }, + expectError: true, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + objects := []runtime.Object{} + if tc.clusterInfo != nil { + objects = append(objects, tc.clusterInfo) + } + clientset := fake.NewSimpleClientset(objects...) + endpoint, err := GetKubePublicEndpoint(clientset) + if err != nil && !tc.expectError { + t.Fatalf("unexpected error: %v", err) + } + if err == nil && tc.expectError { + t.Error("expected error to be returned, received none") + } + if endpoint != tc.expectedEndpoint { + t.Errorf("expected endpoint %s, got %s", tc.expectedEndpoint, endpoint) + } + }) + } + +} + +func kubeconfigFixture(endpoint string) string { + kubeconfig := &clientcmdapiv1.Config{} + if len(endpoint) > 0 { + kubeconfig.Clusters = []clientcmdapiv1.NamedCluster{ + { + Name: "test-kube", + Cluster: clientcmdapiv1.Cluster{ + Server: endpoint, + }, + }, + } + } + configYAML, err := yaml.Marshal(kubeconfig) + if err != nil { + return "" + } + return string(configYAML) +} diff --git a/cmd/util/project.go b/cmd/util/project.go index 12e875492baa9..fa446ceb3b41c 100644 --- a/cmd/util/project.go +++ b/cmd/util/project.go @@ -94,7 +94,7 @@ func (opts *ProjectOpts) GetDestinations() []v1alpha1.ApplicationDestination { return destinations } -// TODO: Get configured keys and emit warning when a key is specified that is not configured +// GetSignatureKeys TODO: Get configured keys and emit warning when a key is specified that is not configured func (opts *ProjectOpts) GetSignatureKeys() []v1alpha1.SignatureKey { signatureKeys := make([]v1alpha1.SignatureKey, 0) for _, keyStr := range opts.SignatureKeys { @@ -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 } @@ -138,7 +138,10 @@ func readProjFromURI(fileURL string, proj *v1alpha1.AppProject) error { } else { err = config.UnmarshalRemoteFile(fileURL, &proj) } - return fmt.Errorf("error reading proj from uri: %w", err) + if err != nil { + return fmt.Errorf("error reading proj from uri: %w", err) + } + return nil } func SetProjSpecOptions(flags *pflag.FlagSet, spec *v1alpha1.AppProjectSpec, projOpts *ProjectOpts) int { diff --git a/cmd/util/repo.go b/cmd/util/repo.go index 87023c3a97206..b60c30a071311 100644 --- a/cmd/util/repo.go +++ b/cmd/util/repo.go @@ -23,6 +23,7 @@ type RepoOptions struct { GitHubAppEnterpriseBaseURL string Proxy string GCPServiceAccountKeyPath string + ForceHttpBasicAuth bool } func AddRepoFlags(command *cobra.Command, opts *RepoOptions) { @@ -44,4 +45,5 @@ func AddRepoFlags(command *cobra.Command, opts *RepoOptions) { command.Flags().StringVar(&opts.GitHubAppEnterpriseBaseURL, "github-app-enterprise-base-url", "", "base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3") command.Flags().StringVar(&opts.Proxy, "proxy", "", "use proxy to access repository") command.Flags().StringVar(&opts.GCPServiceAccountKeyPath, "gcp-service-account-key-path", "", "service account key for the Google Cloud Platform") + command.Flags().BoolVar(&opts.ForceHttpBasicAuth, "force-http-basic-auth", false, "whether to force use of basic auth when connecting repository via HTTP") } diff --git a/cmpserver/apiclient/clientset.go b/cmpserver/apiclient/clientset.go index 6b4c19f0261ff..025625ff8092e 100644 --- a/cmpserver/apiclient/clientset.go +++ b/cmpserver/apiclient/clientset.go @@ -7,7 +7,6 @@ import ( grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry" log "github.com/sirupsen/logrus" - "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -47,8 +46,8 @@ func NewConnection(address string) (*grpc.ClientConn, error) { grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor(retryOpts...)), grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(unaryInterceptors...)), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(MaxGRPCMessageSize), grpc.MaxCallSendMsgSize(MaxGRPCMessageSize)), - grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), - grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), + grpc.WithUnaryInterceptor(grpc_util.OTELUnaryClientInterceptor()), + grpc.WithStreamInterceptor(grpc_util.OTELStreamClientInterceptor()), } dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) diff --git a/cmpserver/apiclient/plugin.pb.go b/cmpserver/apiclient/plugin.pb.go index 4c08ac2511edc..29ebca3ae3afc 100644 --- a/cmpserver/apiclient/plugin.pb.go +++ b/cmpserver/apiclient/plugin.pb.go @@ -318,6 +318,7 @@ func (m *ManifestResponse) GetSourceType() string { type RepositoryResponse struct { IsSupported bool `protobuf:"varint,1,opt,name=isSupported,proto3" json:"isSupported,omitempty"` + IsDiscoveryEnabled bool `protobuf:"varint,2,opt,name=isDiscoveryEnabled,proto3" json:"isDiscoveryEnabled,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -363,6 +364,13 @@ func (m *RepositoryResponse) GetIsSupported() bool { return false } +func (m *RepositoryResponse) GetIsDiscoveryEnabled() bool { + if m != nil { + return m.IsDiscoveryEnabled + } + return false +} + // ParametersAnnouncementResponse contains a list of announcements. This list represents all the parameters which a CMP // is able to accept. type ParametersAnnouncementResponse struct { @@ -472,42 +480,43 @@ func init() { func init() { proto.RegisterFile("cmpserver/plugin/plugin.proto", fileDescriptor_b21875a7079a06ed) } var fileDescriptor_b21875a7079a06ed = []byte{ - // 558 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x54, 0xc1, 0x6e, 0xd3, 0x4c, - 0x10, 0xae, 0x9b, 0xb4, 0x4d, 0x26, 0x95, 0xfe, 0x68, 0xf5, 0x0b, 0x4c, 0xd4, 0x86, 0xe0, 0x03, - 0xca, 0x85, 0x44, 0x32, 0x88, 0x1b, 0x12, 0x2d, 0x2a, 0xad, 0x40, 0x41, 0xd1, 0x96, 0x0b, 0xdc, - 0xb6, 0xce, 0x24, 0x59, 0x6a, 0xef, 0x2e, 0xeb, 0xb5, 0xa5, 0xc0, 0x85, 0xf7, 0xe0, 0x01, 0x78, - 0x15, 0x8e, 0x3c, 0x02, 0xca, 0x93, 0x20, 0xaf, 0xed, 0xd8, 0xa2, 0x6d, 0x38, 0x79, 0xe6, 0x9b, - 0x99, 0x6f, 0xbf, 0x9d, 0x99, 0x35, 0x1c, 0x07, 0x91, 0x8a, 0x51, 0xa7, 0xa8, 0xc7, 0x2a, 0x4c, - 0x16, 0x5c, 0x14, 0x9f, 0x91, 0xd2, 0xd2, 0x48, 0xb2, 0x9f, 0x7b, 0xbd, 0xb3, 0x05, 0x37, 0xcb, - 0xe4, 0x6a, 0x14, 0xc8, 0x68, 0xcc, 0xf4, 0x42, 0x2a, 0x2d, 0x3f, 0x59, 0xe3, 0x49, 0x30, 0x1b, - 0xa7, 0xfe, 0x58, 0xa3, 0x92, 0x05, 0x8d, 0x35, 0xb9, 0x91, 0x7a, 0x55, 0x33, 0x73, 0x3a, 0xef, - 0x9b, 0x03, 0xdd, 0x13, 0xa5, 0x2e, 0x8d, 0x46, 0x16, 0x51, 0xfc, 0x9c, 0x60, 0x6c, 0xc8, 0x0b, - 0x68, 0x45, 0x68, 0xd8, 0x8c, 0x19, 0xe6, 0x3a, 0x03, 0x67, 0xd8, 0xf1, 0x1f, 0x8e, 0x0a, 0x11, - 0x13, 0x26, 0xf8, 0x1c, 0x63, 0x53, 0xa4, 0x4e, 0x8a, 0xb4, 0x8b, 0x1d, 0xba, 0x29, 0x21, 0x1e, - 0x34, 0xe7, 0x3c, 0x44, 0x77, 0xd7, 0x96, 0x1e, 0x96, 0xa5, 0xaf, 0x79, 0x88, 0x17, 0x3b, 0xd4, - 0xc6, 0x4e, 0xdb, 0x70, 0xa0, 0x73, 0x0a, 0xef, 0x87, 0x03, 0xf7, 0xef, 0xa0, 0x25, 0x2e, 0x1c, - 0x30, 0xa5, 0xde, 0xb1, 0x08, 0xad, 0x90, 0x36, 0x2d, 0x5d, 0xd2, 0x07, 0x60, 0x4a, 0x51, 0x0c, - 0xa7, 0xcc, 0x2c, 0xed, 0x51, 0x6d, 0x5a, 0x43, 0x48, 0x0f, 0x5a, 0xc1, 0x12, 0x83, 0xeb, 0x38, - 0x89, 0xdc, 0x86, 0x8d, 0x6e, 0x7c, 0x42, 0xa0, 0x19, 0xf3, 0x2f, 0xe8, 0x36, 0x07, 0xce, 0xb0, - 0x41, 0xad, 0x4d, 0x3c, 0x68, 0xa0, 0x48, 0xdd, 0xbd, 0x41, 0x63, 0xd8, 0xf1, 0xbb, 0xa5, 0xe6, - 0x33, 0x91, 0x9e, 0x09, 0xa3, 0x57, 0x34, 0x0b, 0x7a, 0xcf, 0xa0, 0x55, 0x02, 0x19, 0x87, 0xa8, - 0x64, 0x59, 0x9b, 0xfc, 0x0f, 0x7b, 0x29, 0x0b, 0x13, 0x2c, 0xe4, 0xe4, 0x8e, 0x37, 0x85, 0x6e, - 0x75, 0xbd, 0x58, 0x49, 0x11, 0x23, 0x39, 0x82, 0x76, 0x54, 0x60, 0xb1, 0xeb, 0x0c, 0x1a, 0xc3, - 0x36, 0xad, 0x80, 0xec, 0x6e, 0xb1, 0x4c, 0x74, 0x80, 0xef, 0x57, 0xaa, 0x24, 0xab, 0x21, 0xde, - 0x73, 0x20, 0x74, 0x33, 0xc8, 0x0d, 0xe7, 0x00, 0x3a, 0x3c, 0xbe, 0x4c, 0x94, 0x92, 0xda, 0xe0, - 0xcc, 0x0a, 0x6b, 0xd1, 0x3a, 0xe4, 0x7d, 0x85, 0xfe, 0x94, 0x69, 0x16, 0xa1, 0x41, 0x1d, 0x9f, - 0x08, 0x21, 0x13, 0x11, 0x60, 0x84, 0xa2, 0xd2, 0xf5, 0x01, 0xee, 0xa9, 0x32, 0xa3, 0x9e, 0x90, - 0x8b, 0xec, 0xf8, 0x8f, 0x46, 0xb5, 0x0d, 0x9a, 0xde, 0x96, 0x49, 0xef, 0x20, 0xf0, 0x8e, 0xa0, - 0x99, 0x6d, 0x40, 0xd6, 0xa4, 0x60, 0x99, 0x88, 0x6b, 0x2b, 0xf0, 0x90, 0xe6, 0x8e, 0xff, 0x7d, - 0x17, 0x8e, 0x5f, 0x49, 0x31, 0xe7, 0x8b, 0x09, 0x13, 0x6c, 0x61, 0x6b, 0xa6, 0x76, 0x06, 0x97, - 0xa8, 0x53, 0x1e, 0x20, 0x79, 0x03, 0xdd, 0x73, 0x14, 0xa8, 0x99, 0xc1, 0xb2, 0x9d, 0xc4, 0x2d, - 0xe7, 0xf4, 0xf7, 0x0a, 0xf7, 0xdc, 0x9b, 0x0b, 0x9b, 0x5f, 0xd1, 0xdb, 0x19, 0x3a, 0xe4, 0x2d, - 0xfc, 0x37, 0x61, 0x26, 0x58, 0x56, 0x5d, 0xdc, 0x42, 0xd5, 0x2b, 0x23, 0x37, 0x7b, 0x6e, 0xc9, - 0x18, 0x3c, 0x38, 0x47, 0x73, 0x7b, 0x63, 0xb7, 0xd0, 0x3e, 0x2e, 0x23, 0xdb, 0x47, 0x92, 0x1d, - 0x71, 0xfa, 0xf2, 0xe7, 0xba, 0xef, 0xfc, 0x5a, 0xf7, 0x9d, 0xdf, 0xeb, 0xbe, 0xf3, 0xd1, 0xff, - 0xc7, 0xd3, 0xaf, 0x7e, 0x20, 0x4c, 0xf1, 0x20, 0xe4, 0x28, 0xcc, 0xd5, 0xbe, 0x7d, 0xee, 0x4f, - 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x33, 0x34, 0xb3, 0x95, 0x5e, 0x04, 0x00, 0x00, + // 576 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x94, 0xdd, 0x6e, 0x12, 0x4f, + 0x14, 0xc0, 0xbb, 0x85, 0xb6, 0x70, 0x68, 0xf2, 0x27, 0x93, 0x7f, 0x74, 0x25, 0x2d, 0xe2, 0x5e, + 0x18, 0x6e, 0x84, 0x04, 0xbd, 0x35, 0xb1, 0x55, 0x6c, 0xa3, 0xc1, 0x90, 0xa9, 0x37, 0x7a, 0x37, + 0x1d, 0x0e, 0x30, 0x76, 0x77, 0x66, 0x9c, 0x99, 0xdd, 0x04, 0xbd, 0xf1, 0x3d, 0x7c, 0x00, 0x5f, + 0xc5, 0x4b, 0x1f, 0xc1, 0xf4, 0x49, 0x0c, 0xb3, 0xbb, 0x40, 0x6c, 0x8b, 0x57, 0x7b, 0x3e, 0x7f, + 0x7b, 0xbe, 0x32, 0x70, 0xcc, 0x13, 0x6d, 0xd1, 0x64, 0x68, 0xfa, 0x3a, 0x4e, 0x67, 0x42, 0x16, + 0x9f, 0x9e, 0x36, 0xca, 0x29, 0xb2, 0x9f, 0x6b, 0xad, 0xe1, 0x4c, 0xb8, 0x79, 0x7a, 0xd9, 0xe3, + 0x2a, 0xe9, 0x33, 0x33, 0x53, 0xda, 0xa8, 0x4f, 0x5e, 0x78, 0xc2, 0x27, 0xfd, 0x6c, 0xd0, 0x37, + 0xa8, 0x55, 0x81, 0xf1, 0xa2, 0x70, 0xca, 0x2c, 0x36, 0xc4, 0x1c, 0x17, 0x7d, 0x0b, 0xa0, 0x79, + 0xa2, 0xf5, 0x85, 0x33, 0xc8, 0x12, 0x8a, 0x9f, 0x53, 0xb4, 0x8e, 0x3c, 0x87, 0x5a, 0x82, 0x8e, + 0x4d, 0x98, 0x63, 0x61, 0xd0, 0x09, 0xba, 0x8d, 0xc1, 0xc3, 0x5e, 0x51, 0xc4, 0x88, 0x49, 0x31, + 0x45, 0xeb, 0x8a, 0xd0, 0x51, 0x11, 0x76, 0xbe, 0x43, 0x57, 0x29, 0x24, 0x82, 0xea, 0x54, 0xc4, + 0x18, 0xee, 0xfa, 0xd4, 0xc3, 0x32, 0xf5, 0xb5, 0x88, 0xf1, 0x7c, 0x87, 0x7a, 0xdf, 0x69, 0x1d, + 0x0e, 0x4c, 0x8e, 0x88, 0x7e, 0x04, 0x70, 0xff, 0x0e, 0x2c, 0x09, 0xe1, 0x80, 0x69, 0xfd, 0x8e, + 0x25, 0xe8, 0x0b, 0xa9, 0xd3, 0x52, 0x25, 0x6d, 0x00, 0xa6, 0x35, 0xc5, 0x78, 0xcc, 0xdc, 0xdc, + 0xff, 0xaa, 0x4e, 0x37, 0x2c, 0xa4, 0x05, 0x35, 0x3e, 0x47, 0x7e, 0x65, 0xd3, 0x24, 0xac, 0x78, + 0xef, 0x4a, 0x27, 0x04, 0xaa, 0x56, 0x7c, 0xc1, 0xb0, 0xda, 0x09, 0xba, 0x15, 0xea, 0x65, 0x12, + 0x41, 0x05, 0x65, 0x16, 0xee, 0x75, 0x2a, 0xdd, 0xc6, 0xa0, 0x59, 0xd6, 0x3c, 0x94, 0xd9, 0x50, + 0x3a, 0xb3, 0xa0, 0x4b, 0x67, 0xf4, 0x0c, 0x6a, 0xa5, 0x61, 0xc9, 0x90, 0xeb, 0xb2, 0xbc, 0x4c, + 0xfe, 0x87, 0xbd, 0x8c, 0xc5, 0x29, 0x16, 0xe5, 0xe4, 0x4a, 0x34, 0x86, 0xe6, 0xba, 0x3d, 0xab, + 0x95, 0xb4, 0x48, 0x8e, 0xa0, 0x9e, 0x14, 0x36, 0x1b, 0x06, 0x9d, 0x4a, 0xb7, 0x4e, 0xd7, 0x86, + 0x65, 0x6f, 0x56, 0xa5, 0x86, 0xe3, 0xfb, 0x85, 0x2e, 0x61, 0x1b, 0x96, 0x68, 0x0a, 0x84, 0xae, + 0x16, 0xb9, 0x62, 0x76, 0xa0, 0x21, 0xec, 0x45, 0xaa, 0xb5, 0x32, 0x0e, 0x27, 0xbe, 0xb0, 0x1a, + 0xdd, 0x34, 0x91, 0x1e, 0x10, 0x61, 0x5f, 0x09, 0xcb, 0x55, 0x86, 0x66, 0x31, 0x94, 0xec, 0x32, + 0xc6, 0x89, 0xe7, 0xd7, 0xe8, 0x2d, 0x9e, 0xe8, 0x2b, 0xb4, 0xc7, 0xcc, 0xb0, 0x04, 0x1d, 0x1a, + 0x7b, 0x22, 0xa5, 0x4a, 0x25, 0xc7, 0x04, 0xe5, 0xba, 0x8f, 0x0f, 0x70, 0x4f, 0x97, 0x11, 0x9b, + 0x01, 0x79, 0x53, 0x8d, 0xc1, 0xa3, 0xde, 0xc6, 0xc5, 0x8d, 0x6f, 0x8b, 0xa4, 0x77, 0x00, 0xa2, + 0x23, 0xa8, 0x2e, 0x2f, 0x66, 0x39, 0x54, 0x3e, 0x4f, 0xe5, 0x95, 0x6f, 0xe8, 0x90, 0xe6, 0xca, + 0xe0, 0xfb, 0x2e, 0x1c, 0xbf, 0x54, 0x72, 0x2a, 0x66, 0x23, 0x26, 0xd9, 0xcc, 0xe7, 0x8c, 0xfd, + 0xce, 0x2e, 0xd0, 0x64, 0x82, 0x23, 0x79, 0x03, 0xcd, 0x33, 0x94, 0x68, 0x98, 0xc3, 0x72, 0xfc, + 0x24, 0x2c, 0xf7, 0xfa, 0xf7, 0xc9, 0xb7, 0xc2, 0x9b, 0x07, 0x9e, 0xb7, 0x18, 0xed, 0x74, 0x03, + 0xf2, 0x16, 0xfe, 0x1b, 0x31, 0xc7, 0xe7, 0xeb, 0xa9, 0x6f, 0x41, 0xb5, 0x4a, 0xcf, 0xcd, 0x1d, + 0x79, 0x18, 0x83, 0x07, 0x67, 0xe8, 0x6e, 0x1f, 0xec, 0x16, 0xec, 0xe3, 0xd2, 0xb3, 0x7d, 0x25, + 0xcb, 0x5f, 0x9c, 0xbe, 0xf8, 0x79, 0xdd, 0x0e, 0x7e, 0x5d, 0xb7, 0x83, 0xdf, 0xd7, 0xed, 0xe0, + 0xe3, 0xe0, 0x1f, 0x4f, 0xc5, 0xfa, 0xc1, 0x61, 0x5a, 0xf0, 0x58, 0xa0, 0x74, 0x97, 0xfb, 0xfe, + 0x79, 0x78, 0xfa, 0x27, 0x00, 0x00, 0xff, 0xff, 0x23, 0x88, 0x8e, 0xd3, 0x8e, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1025,6 +1034,16 @@ func (m *RepositoryResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.IsDiscoveryEnabled { + i-- + if m.IsDiscoveryEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } if m.IsSupported { i-- if m.IsSupported { @@ -1247,6 +1266,9 @@ func (m *RepositoryResponse) Size() (n int) { if m.IsSupported { n += 2 } + if m.IsDiscoveryEnabled { + n += 2 + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -1893,6 +1915,26 @@ func (m *RepositoryResponse) Unmarshal(dAtA []byte) error { } } m.IsSupported = bool(v != 0) + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsDiscoveryEnabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlugin + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsDiscoveryEnabled = bool(v != 0) default: iNdEx = preIndex skippy, err := skipPlugin(dAtA[iNdEx:]) diff --git a/cmpserver/plugin/config.go b/cmpserver/plugin/config.go index 9f05043240c83..faa718ff9fd2e 100644 --- a/cmpserver/plugin/config.go +++ b/cmpserver/plugin/config.go @@ -27,14 +27,19 @@ type PluginConfigSpec struct { Generate Command `json:"generate"` Discover Discover `json:"discover"` Parameters Parameters `yaml:"parameters"` + PreserveFileMode bool `json:"preserveFileMode,omitempty"` } -//Discover holds find and fileName +// Discover holds find and fileName type Discover struct { Find Find `json:"find"` FileName string `json:"fileName"` } +func (d Discover) IsDefined() bool { + return d.FileName != "" || d.Find.Glob != "" || len(d.Find.Command.Command) > 0 +} + // Command holds binary path and arguments list type Command struct { Command []string `json:"command,omitempty"` @@ -84,9 +89,7 @@ func ValidatePluginConfig(config PluginConfig) error { if len(config.Spec.Generate.Command) == 0 { return fmt.Errorf("invalid plugin configuration file. spec.generate command should be non-empty") } - if config.Spec.Discover.Find.Glob == "" && len(config.Spec.Discover.Find.Command.Command) == 0 && config.Spec.Discover.FileName == "" { - return fmt.Errorf("invalid plugin configuration file. atleast one of discover.find.command or discover.find.glob or discover.fineName should be non-empty") - } + // discovery field is optional as apps can now specify plugin names directly return nil } diff --git a/cmpserver/plugin/config_test.go b/cmpserver/plugin/config_test.go new file mode 100644 index 0000000000000..9e22dab1d3741 --- /dev/null +++ b/cmpserver/plugin/config_test.go @@ -0,0 +1,215 @@ +package plugin + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/argoproj/argo-cd/v2/common" +) + +func Test_IsDefined(t *testing.T) { + testCases := []struct { + name string + discover Discover + expected bool + }{ + { + name: "empty discover", + discover: Discover{}, + expected: false, + }, + { + name: "discover with find", + discover: Discover{ + Find: Find{ + Glob: "glob", + }, + }, + expected: true, + }, + { + name: "discover with fileName", + discover: Discover{ + FileName: "fileName", + }, + expected: true, + }, + { + name: "discover with empty command", + discover: Discover{ + Find: Find{ + Command: Command{ + Command: []string{}, + }, + }, + }, + expected: false, + }, + { + name: "discover with command", + discover: Discover{ + Find: Find{ + Command: Command{ + Command: []string{"command"}, + }, + }, + }, + expected: true, + }, + } + + for _, tc := range testCases { + tcc := tc + t.Run(tcc.name, func(t *testing.T) { + t.Parallel() + + actual := tcc.discover.IsDefined() + assert.Equal(t, tcc.expected, actual) + }) + } +} + +func Test_ReadPluginConfig(t *testing.T) { + testCases := []struct { + name string + fileContents string + expected *PluginConfig + expectedErr string + }{ + { + name: "empty metadata", + fileContents: ` +metadata: +`, + expected: nil, + expectedErr: "invalid plugin configuration file. metadata.name should be non-empty.", + }, + { + name: "empty metadata name", + fileContents: ` +metadata: + name: "" +`, + expected: nil, + expectedErr: "invalid plugin configuration file. metadata.name should be non-empty.", + }, + { + name: "invalid kind", + fileContents: ` +kind: invalid +metadata: + name: name +`, + expected: nil, + expectedErr: "invalid plugin configuration file. kind should be ConfigManagementPlugin, found invalid", + }, + { + name: "empty generate command", + fileContents: ` +kind: ConfigManagementPlugin +metadata: + name: name +`, + expected: nil, + expectedErr: "invalid plugin configuration file. spec.generate command should be non-empty", + }, + { + name: "valid config", + fileContents: ` +kind: ConfigManagementPlugin +metadata: + name: name +spec: + generate: + command: [command] +`, + expected: &PluginConfig{ + TypeMeta: v1.TypeMeta{ + Kind: ConfigManagementPluginKind, + }, + Metadata: v1.ObjectMeta{ + Name: "name", + }, + Spec: PluginConfigSpec{ + Generate: Command{ + Command: []string{"command"}, + }, + }, + }, + }, + } + + for _, tc := range testCases { + tcc := tc + t.Run(tcc.name, func(t *testing.T) { + t.Parallel() + // write test string to temporary file + tempDir := t.TempDir() + tempFile, err := os.Create(filepath.Join(tempDir, "plugin.yaml")) + require.NoError(t, err) + err = tempFile.Close() + require.NoError(t, err) + err = os.WriteFile(tempFile.Name(), []byte(tcc.fileContents), 0644) + require.NoError(t, err) + config, err := ReadPluginConfig(tempDir) + if tcc.expectedErr != "" { + assert.EqualError(t, err, tcc.expectedErr) + } else { + assert.NoError(t, err) + } + assert.Equal(t, tcc.expected, config) + }) + } +} + +func Test_PluginConfig_Address(t *testing.T) { + testCases := []struct { + name string + config *PluginConfig + expected string + }{ + { + name: "no version specified", + config: &PluginConfig{ + TypeMeta: v1.TypeMeta{ + Kind: ConfigManagementPluginKind, + }, + Metadata: v1.ObjectMeta{ + Name: "name", + }, + }, + expected: "name", + }, + { + name: "version specified", + config: &PluginConfig{ + TypeMeta: v1.TypeMeta{ + Kind: ConfigManagementPluginKind, + }, + Metadata: v1.ObjectMeta{ + Name: "name", + }, + Spec: PluginConfigSpec{ + Version: "version", + }, + }, + expected: "name-version", + }, + } + + for _, tc := range testCases { + tcc := tc + t.Run(tcc.name, func(t *testing.T) { + t.Parallel() + actual := tcc.config.Address() + expectedAddress := fmt.Sprintf("%s/%s.sock", common.GetPluginSockFilePath(), tcc.expected) + assert.Equal(t, expectedAddress, actual) + }) + } +} diff --git a/cmpserver/plugin/plugin.go b/cmpserver/plugin/plugin.go index 5ac87d4ed5274..ca1e7592218ea 100644 --- a/cmpserver/plugin/plugin.go +++ b/cmpserver/plugin/plugin.go @@ -9,8 +9,10 @@ import ( "os" "os/exec" "path/filepath" + "strconv" "strings" "time" + "unicode" "github.com/argoproj/pkg/rand" @@ -22,6 +24,7 @@ import ( "github.com/argoproj/argo-cd/v2/util/io/files" "github.com/argoproj/gitops-engine/pkg/utils/kube" + "github.com/cyphar/filepath-securejoin" "github.com/mattn/go-zglob" log "github.com/sirupsen/logrus" ) @@ -73,9 +76,8 @@ func runCommand(ctx context.Context, command Command, path string, env []string) } logCtx := log.WithFields(log.Fields{"execID": execId}) - // log in a way we can copy-and-paste into a terminal - args := strings.Join(cmd.Args, " ") - logCtx.WithFields(log.Fields{"dir": cmd.Dir}).Info(args) + argsToLog := getCommandArgsToLog(cmd) + logCtx.WithFields(log.Fields{"dir": cmd.Dir}).Info(argsToLog) var stdout bytes.Buffer var stderr bytes.Buffer @@ -95,6 +97,14 @@ func runCommand(ctx context.Context, command Command, path string, env []string) <-ctx.Done() // Kill by group ID to make sure child processes are killed. The - tells `kill` that it's a group ID. // Since we didn't set Pgid in SysProcAttr, the group ID is the same as the process ID. https://pkg.go.dev/syscall#SysProcAttr + + // Sending a TERM signal first to allow any potential cleanup if needed, and then sending a KILL signal + _ = sysCallTerm(-cmd.Process.Pid) + + // modify cleanup timeout to allow process to cleanup + cleanupTimeout := 5 * time.Second + time.Sleep(cleanupTimeout) + _ = sysCallKill(-cmd.Process.Pid) }() @@ -106,14 +116,47 @@ func runCommand(ctx context.Context, command Command, path string, env []string) logCtx.WithFields(log.Fields{"duration": duration}).Debug(output) if err != nil { - err := newCmdError(args, errors.New(err.Error()), strings.TrimSpace(stderr.String())) + err := newCmdError(argsToLog, errors.New(err.Error()), strings.TrimSpace(stderr.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 { + 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 } +// getCommandArgsToLog represents the given command in a way that we can copy-and-paste into a terminal +func getCommandArgsToLog(cmd *exec.Cmd) string { + var argsToLog []string + for _, arg := range cmd.Args { + containsSpace := false + for _, r := range arg { + if unicode.IsSpace(r) { + containsSpace = true + break + } + } + if containsSpace { + // add quotes and escape any internal quotes + argsToLog = append(argsToLog, strconv.Quote(arg)) + } else { + argsToLog = append(argsToLog, arg) + } + } + args := strings.Join(argsToLog, " ") + return args +} + type CmdError struct { Args string Stderr string @@ -153,7 +196,7 @@ func getTempDirMustCleanup(baseDir string) (workDir string, cleanup func(), err if err := os.RemoveAll(workDir); err != nil { log.WithFields(map[string]interface{}{ common.SecurityField: common.SecurityHigh, - common.SecurityCWEField: 459, + common.SecurityCWEField: common.SecurityCWEIncompleteCleanup, }).Errorf("Failed to clean up temp directory: %s", err) } } @@ -184,7 +227,7 @@ func (s *Service) generateManifestGeneric(stream GenerateManifestStream) error { } defer cleanup() - metadata, err := cmp.ReceiveRepoStream(ctx, stream, workDir) + metadata, err := cmp.ReceiveRepoStream(ctx, stream, workDir, s.initConstants.PluginConfig.Spec.PreserveFileMode) if err != nil { return fmt.Errorf("generate manifest error receiving stream: %w", err) } @@ -268,16 +311,16 @@ func (s *Service) matchRepositoryGeneric(stream MatchRepositoryStream) error { } defer cleanup() - metadata, err := cmp.ReceiveRepoStream(bufferedCtx, stream, workDir) + metadata, err := cmp.ReceiveRepoStream(bufferedCtx, stream, workDir, s.initConstants.PluginConfig.Spec.PreserveFileMode) if err != nil { return fmt.Errorf("match repository error receiving stream: %w", err) } - isSupported, err := s.matchRepository(bufferedCtx, workDir, metadata.GetEnv()) + isSupported, isDiscoveryEnabled, err := s.matchRepository(bufferedCtx, workDir, metadata.GetEnv(), metadata.GetAppRelPath()) if err != nil { return fmt.Errorf("match repository error: %w", err) } - repoResponse := &apiclient.RepositoryResponse{IsSupported: isSupported} + repoResponse := &apiclient.RepositoryResponse{IsSupported: isSupported, IsDiscoveryEnabled: isDiscoveryEnabled} err = stream.SendAndClose(repoResponse) if err != nil { @@ -286,50 +329,55 @@ func (s *Service) matchRepositoryGeneric(stream MatchRepositoryStream) error { return nil } -func (s *Service) matchRepository(ctx context.Context, workdir string, envEntries []*apiclient.EnvEntry) (bool, error) { +func (s *Service) matchRepository(ctx context.Context, workdir string, envEntries []*apiclient.EnvEntry, appRelPath string) (isSupported bool, isDiscoveryEnabled bool, err error) { config := s.initConstants.PluginConfig + + appPath, err := securejoin.SecureJoin(workdir, appRelPath) + if err != nil { + log.WithFields(map[string]interface{}{ + common.SecurityField: common.SecurityHigh, + common.SecurityCWEField: common.SecurityCWEIncompleteCleanup, + }).Errorf("error joining workdir %q and appRelPath %q: %v", workdir, appRelPath, err) + } + if config.Spec.Discover.FileName != "" { log.Debugf("config.Spec.Discover.FileName is provided") - pattern := filepath.Join(workdir, config.Spec.Discover.FileName) + pattern := filepath.Join(appPath, config.Spec.Discover.FileName) matches, err := filepath.Glob(pattern) if err != nil { e := fmt.Errorf("error finding filename match for pattern %q: %w", pattern, err) log.Debug(e) - return false, e + return false, true, e } - return len(matches) > 0, nil + return len(matches) > 0, true, nil } if config.Spec.Discover.Find.Glob != "" { log.Debugf("config.Spec.Discover.Find.Glob is provided") - pattern := filepath.Join(workdir, config.Spec.Discover.Find.Glob) + pattern := filepath.Join(appPath, config.Spec.Discover.Find.Glob) // filepath.Glob doesn't have '**' support hence selecting third-party lib // https://github.com/golang/go/issues/11862 matches, err := zglob.Glob(pattern) if err != nil { e := fmt.Errorf("error finding glob match for pattern %q: %w", pattern, err) log.Debug(e) - return false, e + return false, true, e } - if len(matches) > 0 { - return true, nil - } - return false, nil + return len(matches) > 0, true, nil } - log.Debugf("Going to try runCommand.") - env := append(os.Environ(), environ(envEntries)...) - - find, err := runCommand(ctx, config.Spec.Discover.Find.Command, workdir, env) - if err != nil { - return false, fmt.Errorf("error running find command: %w", err) + if len(config.Spec.Discover.Find.Command.Command) > 0 { + log.Debugf("Going to try runCommand.") + env := append(os.Environ(), environ(envEntries)...) + find, err := runCommand(ctx, config.Spec.Discover.Find.Command, appPath, env) + if err != nil { + return false, true, fmt.Errorf("error running find command: %w", err) + } + return find != "", true, nil } - if find != "" { - return true, nil - } - return false, nil + return false, false, nil } // ParametersAnnouncementStream defines an interface able to send/receive a stream of parameter announcements. @@ -349,7 +397,7 @@ func (s *Service) GetParametersAnnouncement(stream apiclient.ConfigManagementPlu } defer cleanup() - metadata, err := cmp.ReceiveRepoStream(bufferedCtx, stream, workDir) + metadata, err := cmp.ReceiveRepoStream(bufferedCtx, stream, workDir, s.initConstants.PluginConfig.Spec.PreserveFileMode) if err != nil { return fmt.Errorf("parameters announcement error receiving stream: %w", err) } @@ -358,7 +406,7 @@ func (s *Service) GetParametersAnnouncement(stream apiclient.ConfigManagementPlu return fmt.Errorf("illegal appPath: out of workDir bound") } - repoResponse, err := getParametersAnnouncement(bufferedCtx, appPath, s.initConstants.PluginConfig.Spec.Parameters.Static, s.initConstants.PluginConfig.Spec.Parameters.Dynamic) + repoResponse, err := getParametersAnnouncement(bufferedCtx, appPath, s.initConstants.PluginConfig.Spec.Parameters.Static, s.initConstants.PluginConfig.Spec.Parameters.Dynamic, metadata.GetEnv()) if err != nil { return fmt.Errorf("get parameters announcement error: %w", err) } @@ -370,11 +418,12 @@ func (s *Service) GetParametersAnnouncement(stream apiclient.ConfigManagementPlu return nil } -func getParametersAnnouncement(ctx context.Context, appDir string, announcements []*repoclient.ParameterAnnouncement, command Command) (*apiclient.ParametersAnnouncementResponse, error) { +func getParametersAnnouncement(ctx context.Context, appDir string, announcements []*repoclient.ParameterAnnouncement, command Command, envEntries []*apiclient.EnvEntry) (*apiclient.ParametersAnnouncementResponse, error) { augmentedAnnouncements := announcements if len(command.Command) > 0 { - stdout, err := runCommand(ctx, command, appDir, os.Environ()) + env := append(os.Environ(), environ(envEntries)...) + stdout, err := runCommand(ctx, command, appDir, env) if err != nil { return nil, fmt.Errorf("error executing dynamic parameter output command: %w", err) } diff --git a/cmpserver/plugin/plugin.proto b/cmpserver/plugin/plugin.proto index b6dc23232e8a1..16d4268d5939f 100644 --- a/cmpserver/plugin/plugin.proto +++ b/cmpserver/plugin/plugin.proto @@ -44,6 +44,7 @@ message ManifestResponse { message RepositoryResponse { bool isSupported = 1; + bool isDiscoveryEnabled = 2; } // ParametersAnnouncementResponse contains a list of announcements. This list represents all the parameters which a CMP diff --git a/cmpserver/plugin/plugin_test.go b/cmpserver/plugin/plugin_test.go index c14de4ccf6328..b253dc414cbdc 100644 --- a/cmpserver/plugin/plugin_test.go +++ b/cmpserver/plugin/plugin_test.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "os" + "os/exec" "path" "path/filepath" "testing" @@ -99,11 +100,12 @@ func TestMatchRepository(t *testing.T) { f := setup(t, withDiscover(d)) // when - match, err := f.service.matchRepository(context.Background(), f.path, f.env) + match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".") // then assert.NoError(t, err) assert.True(t, match) + assert.True(t, discovery) }) t.Run("will not match plugin by filename if file not found", func(t *testing.T) { // given @@ -113,11 +115,12 @@ func TestMatchRepository(t *testing.T) { f := setup(t, withDiscover(d)) // when - match, err := f.service.matchRepository(context.Background(), f.path, f.env) + match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".") // then assert.NoError(t, err) assert.False(t, match) + assert.True(t, discovery) }) t.Run("will not match a pattern with a syntax error", func(t *testing.T) { // given @@ -127,7 +130,7 @@ func TestMatchRepository(t *testing.T) { f := setup(t, withDiscover(d)) // when - _, err := f.service.matchRepository(context.Background(), f.path, f.env) + _, _, err := f.service.matchRepository(context.Background(), f.path, f.env, ".") // then assert.ErrorContains(t, err, "syntax error") @@ -142,11 +145,12 @@ func TestMatchRepository(t *testing.T) { f := setup(t, withDiscover(d)) // when - match, err := f.service.matchRepository(context.Background(), f.path, f.env) + match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".") // then assert.NoError(t, err) assert.True(t, match) + assert.True(t, discovery) }) t.Run("will not match plugin by glob if not found", func(t *testing.T) { // given @@ -158,11 +162,12 @@ func TestMatchRepository(t *testing.T) { f := setup(t, withDiscover(d)) // when - match, err := f.service.matchRepository(context.Background(), f.path, f.env) + match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".") // then assert.NoError(t, err) assert.False(t, match) + assert.True(t, discovery) }) t.Run("will throw an error for a bad pattern", func(t *testing.T) { // given @@ -174,7 +179,7 @@ func TestMatchRepository(t *testing.T) { f := setup(t, withDiscover(d)) // when - _, err := f.service.matchRepository(context.Background(), f.path, f.env) + _, _, err := f.service.matchRepository(context.Background(), f.path, f.env, ".") // then assert.ErrorContains(t, err, "error finding glob match for pattern") @@ -191,11 +196,12 @@ func TestMatchRepository(t *testing.T) { f := setup(t, withDiscover(d)) // when - match, err := f.service.matchRepository(context.Background(), f.path, f.env) + match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".") // then assert.NoError(t, err) assert.True(t, match) + assert.True(t, discovery) }) t.Run("will not match plugin by command when returns no output", func(t *testing.T) { // given @@ -209,11 +215,11 @@ func TestMatchRepository(t *testing.T) { f := setup(t, withDiscover(d)) // when - match, err := f.service.matchRepository(context.Background(), f.path, f.env) - + match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".") // then assert.NoError(t, err) assert.False(t, match) + assert.True(t, discovery) }) t.Run("will match plugin because env var defined", func(t *testing.T) { // given @@ -227,11 +233,12 @@ func TestMatchRepository(t *testing.T) { f := setup(t, withDiscover(d)) // when - match, err := f.service.matchRepository(context.Background(), f.path, f.env) + match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".") // then assert.NoError(t, err) assert.True(t, match) + assert.True(t, discovery) }) t.Run("will not match plugin because no env var defined", func(t *testing.T) { // given @@ -246,11 +253,12 @@ func TestMatchRepository(t *testing.T) { f := setup(t, withDiscover(d)) // when - match, err := f.service.matchRepository(context.Background(), f.path, f.env) + match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".") // then assert.NoError(t, err) assert.False(t, match) + assert.True(t, discovery) }) t.Run("will not match plugin by command when command fails", func(t *testing.T) { // given @@ -264,11 +272,25 @@ func TestMatchRepository(t *testing.T) { f := setup(t, withDiscover(d)) // when - match, err := f.service.matchRepository(context.Background(), f.path, f.env) + match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".") // then assert.Error(t, err) assert.False(t, match) + assert.True(t, discovery) + }) + t.Run("will not match plugin as discovery is not set", func(t *testing.T) { + // given + d := Discover{} + f := setup(t, withDiscover(d)) + + // when + match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".") + + // then + assert.NoError(t, err) + assert.False(t, match) + assert.False(t, discovery) }) } @@ -347,6 +369,28 @@ func TestRunCommandEmptyCommand(t *testing.T) { assert.ErrorContains(t, err, "Command is empty") } +// TestRunCommandContextTimeoutWithGracefulTermination makes sure that the process is given enough time to cleanup before sending SIGKILL. +func TestRunCommandContextTimeoutWithCleanup(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 900*time.Millisecond) + defer cancel() + + // Use a subshell so there's a child command. + // This command sleeps for 4 seconds which is currently less than the 5 second delay between SIGTERM and SIGKILL signal and then exits successfully. + command := Command{ + Command: []string{"sh", "-c"}, + Args: []string{`(trap 'echo "cleanup completed"; exit' TERM; sleep 4)`}, + } + + before := time.Now() + output, err := runCommand(ctx, command, "", []string{}) + after := time.Now() + + assert.Error(t, err) // The command should time out, causing an error. + assert.Less(t, after.Sub(before), 1*time.Second) + // The command should still have completed the cleanup after termination. + assert.Contains(t, output, "cleanup completed") +} + func Test_getParametersAnnouncement_empty_command(t *testing.T) { staticYAML := ` - name: static-a @@ -359,7 +403,7 @@ func Test_getParametersAnnouncement_empty_command(t *testing.T) { Command: []string{"echo"}, Args: []string{`[]`}, } - res, err := getParametersAnnouncement(context.Background(), "", *static, command) + res, err := getParametersAnnouncement(context.Background(), "", *static, command, []*apiclient.EnvEntry{}) require.NoError(t, err) assert.Equal(t, []*repoclient.ParameterAnnouncement{{Name: "static-a"}, {Name: "static-b"}}, res.ParameterAnnouncements) } @@ -373,7 +417,7 @@ func Test_getParametersAnnouncement_no_command(t *testing.T) { err := yaml.Unmarshal([]byte(staticYAML), static) require.NoError(t, err) command := Command{} - res, err := getParametersAnnouncement(context.Background(), "", *static, command) + res, err := getParametersAnnouncement(context.Background(), "", *static, command, []*apiclient.EnvEntry{}) require.NoError(t, err) assert.Equal(t, []*repoclient.ParameterAnnouncement{{Name: "static-a"}, {Name: "static-b"}}, res.ParameterAnnouncements) } @@ -390,7 +434,7 @@ func Test_getParametersAnnouncement_static_and_dynamic(t *testing.T) { Command: []string{"echo"}, Args: []string{`[{"name": "dynamic-a"}, {"name": "dynamic-b"}]`}, } - res, err := getParametersAnnouncement(context.Background(), "", *static, command) + res, err := getParametersAnnouncement(context.Background(), "", *static, command, []*apiclient.EnvEntry{}) require.NoError(t, err) expected := []*repoclient.ParameterAnnouncement{ {Name: "dynamic-a"}, @@ -406,7 +450,7 @@ func Test_getParametersAnnouncement_invalid_json(t *testing.T) { Command: []string{"echo"}, Args: []string{`[`}, } - _, err := getParametersAnnouncement(context.Background(), "", []*repoclient.ParameterAnnouncement{}, command) + _, err := getParametersAnnouncement(context.Background(), "", []*repoclient.ParameterAnnouncement{}, command, []*apiclient.EnvEntry{}) assert.Error(t, err) assert.Contains(t, err.Error(), "unexpected end of JSON input") } @@ -416,7 +460,7 @@ func Test_getParametersAnnouncement_bad_command(t *testing.T) { Command: []string{"exit"}, Args: []string{"1"}, } - _, err := getParametersAnnouncement(context.Background(), "", []*repoclient.ParameterAnnouncement{}, command) + _, err := getParametersAnnouncement(context.Background(), "", []*repoclient.ParameterAnnouncement{}, command, []*apiclient.EnvEntry{}) assert.Error(t, err) assert.Contains(t, err.Error(), "error executing dynamic parameter output command") } @@ -708,16 +752,17 @@ func TestService_GetParametersAnnouncement(t *testing.T) { require.NoError(t, err) t.Run("successful response", func(t *testing.T) { - s, err := NewMockParametersAnnouncementStream("./testdata/kustomize", "./testdata/kustomize", nil) + s, err := NewMockParametersAnnouncementStream("./testdata/kustomize", "./testdata/kustomize", []string{"MUST_BE_SET=yep"}) require.NoError(t, err) err = service.GetParametersAnnouncement(s) require.NoError(t, err) require.NotNil(t, s.response) - require.Len(t, s.response.ParameterAnnouncements, 1) - assert.Equal(t, repoclient.ParameterAnnouncement{Name: "test-param", String_: "test-value"}, *s.response.ParameterAnnouncements[0]) + require.Len(t, s.response.ParameterAnnouncements, 2) + assert.Equal(t, repoclient.ParameterAnnouncement{Name: "dynamic-test-param", String_: "yep"}, *s.response.ParameterAnnouncements[0]) + assert.Equal(t, repoclient.ParameterAnnouncement{Name: "test-param", String_: "test-value"}, *s.response.ParameterAnnouncements[1]) }) t.Run("out of bounds app", func(t *testing.T) { - s, err := NewMockParametersAnnouncementStream("./testdata/kustomize", "./testdata/kustomize", nil) + s, err := NewMockParametersAnnouncementStream("./testdata/kustomize", "./testdata/kustomize", []string{"MUST_BE_SET=yep"}) require.NoError(t, err) // set a malicious app path on the metadata s.metadataRequest.Request.(*apiclient.AppStreamRequest_Metadata).Metadata.AppRelPath = "../out-of-bounds" @@ -725,4 +770,38 @@ func TestService_GetParametersAnnouncement(t *testing.T) { require.ErrorContains(t, err, "illegal appPath") require.Nil(t, s.response) }) + t.Run("fails when script fails", func(t *testing.T) { + s, err := NewMockParametersAnnouncementStream("./testdata/kustomize", "./testdata/kustomize", []string{"WRONG_ENV_VAR=oops"}) + require.NoError(t, err) + err = service.GetParametersAnnouncement(s) + require.ErrorContains(t, err, "error executing dynamic parameter output command") + require.Nil(t, s.response) + }) +} + +func Test_getCommandArgsToLog(t *testing.T) { + testCases := []struct { + name string + args []string + expected string + }{ + { + name: "no spaces", + args: []string{"sh", "-c", "cat"}, + expected: "sh -c cat", + }, + { + name: "spaces", + args: []string{"sh", "-c", `echo "hello world"`}, + expected: `sh -c "echo \"hello world\""`, + }, + } + + for _, tc := range testCases { + tcc := tc + t.Run(tcc.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, tcc.expected, getCommandArgsToLog(exec.Command(tcc.args[0], tcc.args[1:]...))) + }) + } } diff --git a/cmpserver/plugin/plugin_unix.go b/cmpserver/plugin/plugin_unix.go index a9dc157bc7ef8..ea6b7b5493910 100644 --- a/cmpserver/plugin/plugin_unix.go +++ b/cmpserver/plugin/plugin_unix.go @@ -14,3 +14,7 @@ func newSysProcAttr(setpgid bool) *syscall.SysProcAttr { func sysCallKill(pid int) error { return syscall.Kill(pid, syscall.SIGKILL) } + +func sysCallTerm(pid int) error { + return syscall.Kill(pid, syscall.SIGTERM) +} diff --git a/cmpserver/plugin/plugin_windows.go b/cmpserver/plugin/plugin_windows.go index 2a188e61f6f9e..b8873a9793601 100644 --- a/cmpserver/plugin/plugin_windows.go +++ b/cmpserver/plugin/plugin_windows.go @@ -14,3 +14,7 @@ func newSysProcAttr(setpgid bool) *syscall.SysProcAttr { func sysCallKill(pid int) error { return nil } + +func sysCallTerm(pid int) error { + return nil +} diff --git a/cmpserver/plugin/testdata/kustomize/config/plugin.yaml b/cmpserver/plugin/testdata/kustomize/config/plugin.yaml index addc30c7b4c21..bdca45e9ae45e 100644 --- a/cmpserver/plugin/testdata/kustomize/config/plugin.yaml +++ b/cmpserver/plugin/testdata/kustomize/config/plugin.yaml @@ -5,9 +5,15 @@ metadata: spec: version: v1.0 init: - command: [kustomize, version] + command: [sh, -c] + args: + - | + kustomize version generate: - command: [sh, -c, "kustomize build"] + command: [sh, -c] + args: + - | + kustomize build discover: find: command: [sh, -c, find . -name kustomization.yaml] @@ -16,3 +22,12 @@ spec: static: - name: test-param string: test-value + dynamic: + command: [sh, -c] + args: + - | + # Make sure env vars are making it to the plugin. + if [ -z "$MUST_BE_SET" ]; then + exit 1 + fi + echo "[{\"name\": \"dynamic-test-param\", \"string\": \"$MUST_BE_SET\"}]" 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 5c76bd8f54f32..f4b176946bcbd 100644 --- a/common/common.go +++ b/common/common.go @@ -1,12 +1,20 @@ package common import ( + "errors" "os" "path/filepath" "strconv" "time" "github.com/sirupsen/logrus" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// Component names +const ( + ApplicationController = "argocd-application-controller" ) // Default service addresses and URLS of Argo CD internal services @@ -26,11 +34,13 @@ const ( ArgoCDNotificationsConfigMapName = "argocd-notifications-cm" ArgoCDNotificationsSecretName = "argocd-notifications-secret" ArgoCDRBACConfigMapName = "argocd-rbac-cm" - // Contains SSH known hosts data for connecting repositories. Will get mounted as volume to pods + // ArgoCDKnownHostsConfigMapName contains SSH known hosts data for connecting repositories. Will get mounted as volume to pods ArgoCDKnownHostsConfigMapName = "argocd-ssh-known-hosts-cm" - // Contains TLS certificate data for connecting repositories. Will get mounted as volume to pods + // ArgoCDTLSCertsConfigMapName contains TLS certificate data for connecting repositories. Will get mounted as volume to pods ArgoCDTLSCertsConfigMapName = "argocd-tls-certs-cm" ArgoCDGPGKeysConfigMapName = "argocd-gpg-keys-cm" + // ArgoCDAppControllerShardConfigMapName contains the application controller to shard mapping + ArgoCDAppControllerShardConfigMapName = "argocd-app-controller-shard-cm" ) // Some default configurables @@ -48,28 +58,32 @@ const ( DefaultPortRepoServerMetrics = 8084 ) -// Default listener address for ArgoCD components +// DefaultAddressAPIServer for ArgoCD components const ( - DefaultAddressAPIServer = "localhost" + DefaultAddressAdminDashboard = "localhost" + DefaultAddressAPIServer = "0.0.0.0" + DefaultAddressAPIServerMetrics = "0.0.0.0" + DefaultAddressRepoServer = "0.0.0.0" + DefaultAddressRepoServerMetrics = "0.0.0.0" ) // Default paths on the pod's file system const ( - // The default path where TLS certificates for repositories are located + // DefaultPathTLSConfig is the default path where TLS certificates for repositories are located DefaultPathTLSConfig = "/app/config/tls" - // The default path where SSH known hosts are stored + // DefaultPathSSHConfig is the default path where SSH known hosts are stored DefaultPathSSHConfig = "/app/config/ssh" - // Default name for the SSH known hosts file + // DefaultSSHKnownHostsName is the Default name for the SSH known hosts file DefaultSSHKnownHostsName = "ssh_known_hosts" - // Default path to GnuPG home directory + // DefaultGnuPgHomePath is the Default path to GnuPG home directory DefaultGnuPgHomePath = "/app/config/gpg/keys" - // Default path to repo server TLS endpoint config + // DefaultAppConfigPath is the Default path to repo server TLS endpoint config DefaultAppConfigPath = "/app/config" - // Default path to cmp server plugin socket file + // DefaultPluginSockFilePath is the Default path to cmp server plugin socket file DefaultPluginSockFilePath = "/home/argocd/cmp-server/plugins" - // Default path to cmp server plugin configuration file + // DefaultPluginConfigFilePath is the Default path to cmp server plugin configuration file DefaultPluginConfigFilePath = "/home/argocd/cmp-server/config" - // Plugin Config File is a ConfigManagementPlugin manifest located inside the plugin container + // PluginConfigFileName is the Plugin Config File is a ConfigManagementPlugin manifest located inside the plugin container PluginConfigFileName = "plugin.yaml" ) @@ -96,6 +110,14 @@ const ( // PasswordPatten is the default password patten PasswordPatten = `^.{8,32}$` + + // LegacyShardingAlgorithm is the default value for Sharding Algorithm it uses an `uid` based distribution (non-uniform) + 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" + // 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 @@ -125,10 +147,16 @@ const ( // LabelKeyAppInstance is the label key to use to uniquely identify the instance of an application // The Argo CD application name is used as the instance name LabelKeyAppInstance = "app.kubernetes.io/instance" + // LabelKeyAppName is the label key to use to uniquely identify the name of the Kubernetes application + LabelKeyAppName = "app.kubernetes.io/name" + // LabelKeyAutoLabelClusterInfo if set to true will automatically add extra labels from the cluster info (currently it only adds a k8s version label) + LabelKeyAutoLabelClusterInfo = "argocd.argoproj.io/auto-label-cluster-info" // LabelKeyLegacyApplicationName is the legacy label (v0.10 and below) and is superseded by 'app.kubernetes.io/instance' LabelKeyLegacyApplicationName = "applications.argoproj.io/app-name" // LabelKeySecretType contains the type of argocd secret (currently: 'cluster', 'repository', 'repo-config' or 'repo-creds') LabelKeySecretType = "argocd.argoproj.io/secret-type" + // LabelKeyClusterKubernetesVersion contains the kubernetes version of the cluster secret if it has been enabled + LabelKeyClusterKubernetesVersion = "argocd.argoproj.io/kubernetes-version" // LabelValueSecretTypeCluster indicates a secret type of cluster LabelValueSecretTypeCluster = "cluster" // LabelValueSecretTypeRepository indicates a secret type of repository @@ -136,7 +164,7 @@ const ( // LabelValueSecretTypeRepoCreds indicates a secret type of repository credentials LabelValueSecretTypeRepoCreds = "repo-creds" - // The Argo CD application name is used as the instance name + // AnnotationKeyAppInstance is the Argo CD application name is used as the instance name AnnotationKeyAppInstance = "argocd.argoproj.io/tracking-id" // AnnotationCompareOptions is a comma-separated list of options for comparison @@ -156,6 +184,14 @@ const ( // Ex: "http://grafana.example.com/d/yu5UH4MMz/deployments" // Ex: "Go to Dashboard|http://grafana.example.com/d/yu5UH4MMz/deployments" AnnotationKeyLinkPrefix = "link.argocd.argoproj.io/" + + // AnnotationKeyAppSkipReconcile tells the Application to skip the Application controller reconcile. + // Skip reconcile when the value is "true" or any other string values that can be strconv.ParseBool() to be true. + AnnotationKeyAppSkipReconcile = "argocd.argoproj.io/skip-reconcile" + // LabelKeyComponentRepoServer is the label key to identify the component as repo-server + LabelKeyComponentRepoServer = "app.kubernetes.io/component" + // LabelValueComponentRepoServer is the label value for the repo-server component + LabelValueComponentRepoServer = "repo-server" ) // Environment variables for tuning and debugging Argo CD @@ -164,19 +200,19 @@ const ( EnvVarSSODebug = "ARGOCD_SSO_DEBUG" // EnvVarRBACDebug is an environment variable to enable additional RBAC debugging in the API server EnvVarRBACDebug = "ARGOCD_RBAC_DEBUG" - // Overrides the location where SSH known hosts for repo access data is stored + // EnvVarSSHDataPath overrides the location where SSH known hosts for repo access data is stored EnvVarSSHDataPath = "ARGOCD_SSH_DATA_PATH" - // Overrides the location where TLS certificate for repo access data is stored + // EnvVarTLSDataPath overrides the location where TLS certificate for repo access data is stored EnvVarTLSDataPath = "ARGOCD_TLS_DATA_PATH" - // Specifies number of git remote operations attempts count + // EnvGitAttemptsCount specifies number of git remote operations attempts count EnvGitAttemptsCount = "ARGOCD_GIT_ATTEMPTS_COUNT" - // Specifices max duration of git remote operation retry + // EnvGitRetryMaxDuration specifices max duration of git remote operation retry EnvGitRetryMaxDuration = "ARGOCD_GIT_RETRY_MAX_DURATION" - // Specifies duration of git remote operation retry + // EnvGitRetryDuration specifies duration of git remote operation retry EnvGitRetryDuration = "ARGOCD_GIT_RETRY_DURATION" - // Specifies fator of git remote operation retry + // EnvGitRetryFactor specifies fator of git remote operation retry EnvGitRetryFactor = "ARGOCD_GIT_RETRY_FACTOR" - // Overrides git submodule support, true by default + // EnvGitSubmoduleEnabled overrides git submodule support, true by default EnvGitSubmoduleEnabled = "ARGOCD_GIT_MODULES_ENABLED" // EnvGnuPGHome is the path to ArgoCD's GnuPG keyring for signature verification EnvGnuPGHome = "ARGOCD_GNUPGHOME" @@ -190,20 +226,28 @@ const ( EnvPauseGenerationRequests = "ARGOCD_PAUSE_GEN_REQUESTS" // EnvControllerReplicas is the number of controller replicas EnvControllerReplicas = "ARGOCD_CONTROLLER_REPLICAS" + // EnvControllerHeartbeatTime will update the heartbeat for application controller to claim shard + EnvControllerHeartbeatTime = "ARGOCD_CONTROLLER_HEARTBEAT_TIME" // EnvControllerShard is the shard number that should be handled by controller EnvControllerShard = "ARGOCD_CONTROLLER_SHARD" + // EnvControllerShardingAlgorithm is the distribution sharding algorithm to be used: legacy or round-robin + EnvControllerShardingAlgorithm = "ARGOCD_CONTROLLER_SHARDING_ALGORITHM" + //EnvEnableDynamicClusterDistribution enables dynamic sharding (ALPHA) + EnvEnableDynamicClusterDistribution = "ARGOCD_ENABLE_DYNAMIC_CLUSTER_DISTRIBUTION" // EnvEnableGRPCTimeHistogramEnv enables gRPC metrics collection EnvEnableGRPCTimeHistogramEnv = "ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM" // EnvGithubAppCredsExpirationDuration controls the caching of Github app credentials. This value is in minutes (default: 60) EnvGithubAppCredsExpirationDuration = "ARGOCD_GITHUB_APP_CREDS_EXPIRATION_DURATION" // EnvHelmIndexCacheDuration controls how the helm repository index file is cached for (default: 0) EnvHelmIndexCacheDuration = "ARGOCD_HELM_INDEX_CACHE_DURATION" - // EnvRepoServerConfigPath allows to override the configuration path for repo server + // EnvAppConfigPath allows to override the configuration path for repo server EnvAppConfigPath = "ARGOCD_APP_CONF_PATH" // EnvLogFormat log format that is defined by `--logformat` option EnvLogFormat = "ARGOCD_LOG_FORMAT" // EnvLogLevel log level that is defined by `--loglevel` option EnvLogLevel = "ARGOCD_LOG_LEVEL" + // EnvLogFormatEnableFullTimestamp enables the FullTimestamp option in logs + EnvLogFormatEnableFullTimestamp = "ARGOCD_LOG_FORMAT_ENABLE_FULL_TIMESTAMP" // EnvMaxCookieNumber max number of chunks a cookie can be broken into EnvMaxCookieNumber = "ARGOCD_MAX_COOKIE_NUMBER" // EnvPluginSockFilePath allows to override the pluginSockFilePath for repo server and cmp server @@ -212,6 +256,23 @@ const ( EnvCMPChunkSize = "ARGOCD_CMP_CHUNK_SIZE" // EnvCMPWorkDir defines the full path of the work directory used by the CMP server EnvCMPWorkDir = "ARGOCD_CMP_WORKDIR" + // EnvGPGDataPath overrides the location where GPG keyring for signature verification is stored + EnvGPGDataPath = "ARGOCD_GPG_DATA_PATH" + // EnvServerName is the name of the Argo CD server component, as specified by the value under the LabelKeyAppName label key. + EnvServerName = "ARGOCD_SERVER_NAME" + // EnvRepoServerName is the name of the Argo CD repo server component, as specified by the value under the LabelKeyAppName label key. + EnvRepoServerName = "ARGOCD_REPO_SERVER_NAME" + // EnvAppControllerName is the name of the Argo CD application controller component, as specified by the value under the LabelKeyAppName label key. + EnvAppControllerName = "ARGOCD_APPLICATION_CONTROLLER_NAME" + // EnvRedisName is the name of the Argo CD redis component, as specified by the value under the LabelKeyAppName label key. + 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 @@ -222,13 +283,7 @@ const ( // DefaultCMPWorkDirName defines the work directory name used by the cmp-server DefaultCMPWorkDirName = "_cmp_server" - ConfigMapPluginDeprecationWarning = "argocd-cm plugins are deprecated, and support will be removed in v2.6. Upgrade your plugin to be installed via sidecar. https://argo-cd.readthedocs.io/en/stable/user-guide/config-management-plugins/" - - ConfigMapPluginCLIDeprecationWarning = "spec.plugin.name is set, which means this Application uses a plugin installed in the " + - "argocd-cm ConfigMap. Installing plugins via that ConfigMap is deprecated in Argo CD v2.5. " + - "Starting in Argo CD v2.6, this Application will fail to sync. Contact your Argo CD admin " + - "to make sure an upgrade plan is in place. More info: " + - "https://argo-cd.readthedocs.io/en/latest/operator-manual/upgrading/2.4-2.5/" + ConfigMapPluginDeprecationWarning = "argocd-cm plugins are deprecated, and support will be removed in v2.7. Upgrade your plugin to be installed via sidecar. https://argo-cd.readthedocs.io/en/stable/user-guide/config-management-plugins/" ) const ( @@ -253,6 +308,16 @@ const ( DefaultGitRetryFactor = int64(2) ) +// Constants represent the pod selector labels of the Argo CD component names. These values are determined by the +// installation manifests. +const ( + DefaultServerName = "argocd-server" + DefaultRepoServerName = "argocd-repo-server" + DefaultApplicationControllerName = "argocd-application-controller" + DefaultRedisName = "argocd-redis" + DefaultRedisHaProxyName = "argocd-redis-ha-haproxy" +) + // GetGnuPGHomePath retrieves the path to use for GnuPG home directory, which is either taken from GNUPGHOME environment or a default value func GetGnuPGHomePath() string { if gnuPgHome := os.Getenv(EnvGnuPGHome); gnuPgHome == "" { @@ -295,24 +360,49 @@ func GetCMPWorkDir() string { } const ( - // AnnotationApplicationRefresh is an annotation that is added when an ApplicationSet is requested to be refreshed by a webhook. The ApplicationSet controller will remove this annotation at the end of reconciliation. + // AnnotationApplicationSetRefresh is an annotation that is added when an ApplicationSet is requested to be refreshed by a webhook. The ApplicationSet controller will remove this annotation at the end of reconciliation. AnnotationApplicationSetRefresh = "argocd.argoproj.io/application-set-refresh" ) // gRPC settings const ( - GRPCKeepAliveEnforcementMinimum = 10 * time.Second - // Keep alive 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" - SecurityCWEField = "CWE" - SecurityEmergency = 5 // Indicates unmistakably malicious events that should NEVER occur accidentally and indicates an active attack (i.e. brute forcing, DoS) - SecurityCritical = 4 // Indicates any malicious or exploitable event that had a side effect (i.e. secrets being left behind on the filesystem) - SecurityHigh = 3 // Indicates likely malicious events but one that had no side effects or was blocked (i.e. out of bounds symlinks in repos) - SecurityMedium = 2 // Could indicate malicious events, but has a high likelihood of being user/system error (i.e. access denied) - SecurityLow = 1 // Unexceptional entries (i.e. successful access logs) + SecurityField = "security" + // SecurityCWEField is the logs field for the CWE associated with a log line. CWE stands for Common Weakness Enumeration. See https://cwe.mitre.org/ + SecurityCWEField = "CWE" + SecurityCWEIncompleteCleanup = 459 + SecurityCWEMissingReleaseOfFileDescriptor = 775 + SecurityEmergency = 5 // Indicates unmistakably malicious events that should NEVER occur accidentally and indicates an active attack (i.e. brute forcing, DoS) + SecurityCritical = 4 // Indicates any malicious or exploitable event that had a side effect (i.e. secrets being left behind on the filesystem) + SecurityHigh = 3 // Indicates likely malicious events but one that had no side effects or was blocked (i.e. out of bounds symlinks in repos) + SecurityMedium = 2 // Could indicate malicious events, but has a high likelihood of being user/system error (i.e. access denied) + SecurityLow = 1 // Unexceptional entries (i.e. successful access logs) ) + +// TokenVerificationError is a generic error message for a failure to verify a JWT +const TokenVerificationError = "failed to verify the token" + +var TokenVerificationErr = errors.New(TokenVerificationError) + +var PermissionDeniedAPIError = status.Error(codes.PermissionDenied, "permission denied") 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/common/version.go b/common/version.go index 8598f98c3171d..e8caf37a30601 100644 --- a/common/version.go +++ b/common/version.go @@ -16,6 +16,7 @@ var ( gitTag = "" // output from `git describe --exact-match --tags HEAD` (if clean tree state) gitTreeState = "" // determined from `git status --porcelain`. either 'clean' or 'dirty' kubectlVersion = "" // determined from go.mod file + extraBuildInfo = "" // extra build information for vendors to populate during build ) // Version contains Argo version information @@ -29,6 +30,7 @@ type Version struct { Compiler string Platform string KubectlVersion string + ExtraBuildInfo string } func (v Version) String() string { @@ -66,6 +68,7 @@ func GetVersion() Version { versionStr += "+unknown" } } + return Version{ Version: versionStr, BuildDate: buildDate, @@ -76,5 +79,6 @@ func GetVersion() Version { Compiler: runtime.Compiler, Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), KubectlVersion: kubectlVersion, + ExtraBuildInfo: extraBuildInfo, } } diff --git a/controller/appcontroller.go b/controller/appcontroller.go index 58d0f0aa74bf5..9d89b6e6b37d6 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" @@ -18,6 +20,7 @@ import ( "github.com/argoproj/gitops-engine/pkg/diff" "github.com/argoproj/gitops-engine/pkg/health" synccommon "github.com/argoproj/gitops-engine/pkg/sync/common" + resourceutil "github.com/argoproj/gitops-engine/pkg/sync/resource" "github.com/argoproj/gitops-engine/pkg/utils/kube" jsonpatch "github.com/evanphx/json-patch" log "github.com/sirupsen/logrus" @@ -33,12 +36,16 @@ import ( "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/informers" + informerv1 "k8s.io/client-go/informers/apps/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" "k8s.io/client-go/util/workqueue" + "github.com/argoproj/argo-cd/v2/common" statecache "github.com/argoproj/argo-cd/v2/controller/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" appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned" @@ -47,16 +54,23 @@ import ( "github.com/argoproj/argo-cd/v2/reposerver/apiclient" "github.com/argoproj/argo-cd/v2/util/argo" argodiff "github.com/argoproj/argo-cd/v2/util/argo/diff" + "github.com/argoproj/argo-cd/v2/util/env" + + 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" "github.com/argoproj/argo-cd/v2/util/glob" + "github.com/argoproj/argo-cd/v2/util/helm" logutils "github.com/argoproj/argo-cd/v2/util/log" settings_util "github.com/argoproj/argo-cd/v2/util/settings" ) const ( - updateOperationStateTimeout = 1 * time.Second + updateOperationStateTimeout = 1 * time.Second + defaultDeploymentInformerResyncDuration = 10 * time.Second // orphanedIndex contains application which monitor orphaned resources by namespace orphanedIndex = "orphaned" ) @@ -103,6 +117,7 @@ type ApplicationController struct { stateCache statecache.LiveStateCache statusRefreshTimeout time.Duration statusHardRefreshTimeout time.Duration + statusRefreshJitter time.Duration selfHealTimeout time.Duration repoClientset apiclient.Clientset db db.ArgoDB @@ -111,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. @@ -127,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, "argocd-application-controller"), - 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) @@ -168,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()) } @@ -180,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()) } @@ -188,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()) @@ -195,11 +227,46 @@ func NewApplicationController( } }, }) - metricsAddr := fmt.Sprintf("0.0.0.0:%d", metricsPort) - var err error - ctrl.metricsServer, err = metrics.NewMetricsServer(metricsAddr, appLister, ctrl.canProcessApp, func(r *http.Request) error { + if err != nil { + return nil, err + } + + factory := informers.NewSharedInformerFactoryWithOptions(ctrl.kubeClientset, defaultDeploymentInformerResyncDuration, informers.WithNamespace(settingsMgr.GetNamespace())) + + 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 { + 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) + } + } + 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 - }, metricsApplicationLabels) + } + + metricsAddr := fmt.Sprintf("0.0.0.0:%d", metricsPort) + + ctrl.metricsServer, err = metrics.NewMetricsServer(metricsAddr, appLister, ctrl.canProcessApp, readinessHealthCheck, metricsApplicationLabels) if err != nil { return nil, err } @@ -209,11 +276,12 @@ 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 + ctrl.deploymentInformer = deploymentInformer ctrl.appStateManager = appStateManager ctrl.stateCache = stateCache @@ -226,10 +294,12 @@ func (ctrl *ApplicationController) InvalidateProjectsCache(names ...string) { ctrl.projByNameCache.Delete(name) } } else { - ctrl.projByNameCache.Range(func(key, _ interface{}) bool { - ctrl.projByNameCache.Delete(key) - return true - }) + if ctrl != nil { + ctrl.projByNameCache.Range(func(key, _ interface{}) bool { + ctrl.projByNameCache.Delete(key) + return true + }) + } } } @@ -335,7 +405,7 @@ func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]b } if !ctrl.canProcessApp(obj) { - // Don't force refresh app if app belongs to a different controller shard + // Don't force refresh app if app belongs to a different controller shard or is outside the allowed namespaces. continue } @@ -351,17 +421,20 @@ func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]b level = CompareWithRecent } - // Additional check for debug level so we don't need to evaluate the - // format string in case of non-debug scenarios - if log.GetLevel() >= log.DebugLevel { - var resKey string - if ref.Namespace != "" { - resKey = ref.Namespace + "/" + ref.Name - } else { - resKey = "(cluster-scoped)/" + ref.Name - } - log.Debugf("Refreshing app %s for change in cluster of object %s of type %s/%s", appKey, resKey, ref.APIVersion, ref.Kind) + namespace := ref.Namespace + if ref.Namespace == "" { + namespace = "(cluster-scoped)" } + log.WithFields(log.Fields{ + "application": appKey, + "level": level, + "namespace": namespace, + "name": ref.Name, + "api-version": ref.APIVersion, + "kind": ref.Kind, + "server": app.Spec.Destination.Server, + "cluster-name": app.Spec.Destination.Name, + }).Debug("Requesting app refresh caused by object update") ctrl.requestAppRefresh(app.QualifiedName(), &level, nil) } @@ -437,13 +510,13 @@ func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managed if err != nil { return nil, fmt.Errorf("failed to unmarshal live state of managed resources: %w", err) } - var target = &unstructured.Unstructured{} - err = json.Unmarshal([]byte(managedResource.TargetState), &target) - if err != nil { - return nil, fmt.Errorf("failed to unmarshal target state of managed resources: %w", err) - } if live == nil { + var target = &unstructured.Unstructured{} + err = json.Unmarshal([]byte(managedResource.TargetState), &target) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal target state of managed resources: %w", err) + } nodes = append(nodes, appv1.ResourceNode{ ResourceRef: appv1.ResourceRef{ Version: target.GroupVersionKind().Version, @@ -714,6 +787,24 @@ func (ctrl *ApplicationController) Run(ctx context.Context, statusProcessors int go ctrl.appInformer.Run(ctx.Done()) go ctrl.projInformer.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 { + appItems, err := ctrl.getAppList(metav1.ListOptions{}) + + if err != nil { + log.Warnf("Cannot init sharding. Error while querying application list from database: %v", err) + } else { + ctrl.clusterSharding.Init(clusters, appItems) + } + } + errors.CheckError(ctrl.stateCache.Init()) if !cache.WaitForCacheSync(ctx.Done(), ctrl.appInformer.HasSynced, ctrl.projInformer.HasSynced) { @@ -767,8 +858,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) } } } @@ -827,17 +918,16 @@ 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(), }) message := fmt.Sprintf("Unable to delete application resources: %v", err.Error()) - ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonStatusRefreshed, Type: v1.EventTypeWarning}, message) + ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonStatusRefreshed, Type: v1.EventTypeWarning}, message, "") } } return @@ -941,7 +1031,9 @@ func (ctrl *ApplicationController) removeProjectFinalizer(proj *appv1.AppProject // shouldBeDeleted returns whether a given resource obj should be deleted on cascade delete of application app func (ctrl *ApplicationController) shouldBeDeleted(app *appv1.Application, obj *unstructured.Unstructured) bool { - return !kube.IsCRD(obj) && !isSelfReferencedApp(app, kube.GetObjectRef(obj)) + return !kube.IsCRD(obj) && !isSelfReferencedApp(app, kube.GetObjectRef(obj)) && + !resourceutil.HasAnnotationOption(obj, synccommon.AnnotationSyncOptions, synccommon.SyncOptionDisableDeletion) && + !resourceutil.HasAnnotationOption(obj, helm.ResourcePolicyAnnotation, helm.ResourcePolicyKeep) } func (ctrl *ApplicationController) getPermittedAppLiveObjects(app *appv1.Application, proj *appv1.AppProject, projectClusters func(project string) ([]*appv1.Cluster, error)) (map[kube.ResourceKey]*unstructured.Unstructured, error) { @@ -964,57 +1056,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 + return 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 - } - - 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]) { @@ -1022,8 +1120,6 @@ func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Applic } } - config := metrics.AddMetricsTransportWrapper(ctrl.metricsServer, app, cluster.RESTConfig()) - filteredObjs := FilterObjectsForDeletion(objs) propagationPolicy := metav1.DeletePropagationForeground @@ -1037,12 +1133,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 { @@ -1052,38 +1148,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{}{ @@ -1235,76 +1360,106 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli } func (ctrl *ApplicationController) setOperationState(app *appv1.Application, state *appv1.OperationState) { - kube.RetryUntilSucceed(context.Background(), updateOperationStateTimeout, "Update application operation state", logutils.NewLogrusLogger(logutils.NewWithCurrentConfig()), func() error { - if state.Phase == "" { - // expose any bugs where we neglect to set phase - panic("no phase was set") - } - if state.Phase.Completed() { - now := metav1.Now() - state.FinishedAt = &now - } - patch := map[string]interface{}{ - "status": map[string]interface{}{ - "operationState": state, - }, - } - if state.Phase.Completed() { - // If operation is completed, clear the operation field to indicate no operation is - // in progress. - patch["operation"] = nil - } - if reflect.DeepEqual(app.Status.OperationState, state) { - log.Infof("No operation updates necessary to '%s'. Skipping patch", app.QualifiedName()) - return nil - } - patchJSON, err := json.Marshal(patch) + logCtx := log.WithFields(log.Fields{"application": app.Name, "appNamespace": app.Namespace, "project": app.Spec.Project}) + + if state.Phase == "" { + // expose any bugs where we neglect to set phase + panic("no phase was set") + } + if state.Phase.Completed() { + now := metav1.Now() + state.FinishedAt = &now + } + patch := map[string]interface{}{ + "status": map[string]interface{}{ + "operationState": state, + }, + } + if state.Phase.Completed() { + // If operation is completed, clear the operation field to indicate no operation is + // in progress. + patch["operation"] = nil + } + if reflect.DeepEqual(app.Status.OperationState, state) { + logCtx.Infof("No operation updates necessary to '%s'. Skipping patch", app.QualifiedName()) + return + } + patchJSON, err := json.Marshal(patch) + if err != nil { + logCtx.Errorf("error marshaling json: %v", err) + return + } + if app.Status.OperationState != nil && app.Status.OperationState.FinishedAt != nil && state.FinishedAt == nil { + patchJSON, err = jsonpatch.MergeMergePatches(patchJSON, []byte(`{"status": {"operationState": {"finishedAt": null}}}`)) if err != nil { - return fmt.Errorf("error marshaling json: %w", err) - } - if app.Status.OperationState != nil && app.Status.OperationState.FinishedAt != nil && state.FinishedAt == nil { - patchJSON, err = jsonpatch.MergeMergePatches(patchJSON, []byte(`{"status": {"operationState": {"finishedAt": null}}}`)) - if err != nil { - return fmt.Errorf("error merging operation state patch: %w", err) - } + logCtx.Errorf("error merging operation state patch: %v", err) + return } + } - appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace) - _, err = appClient.Patch(context.Background(), app.Name, types.MergePatchType, patchJSON, metav1.PatchOptions{}) + kube.RetryUntilSucceed(context.Background(), updateOperationStateTimeout, "Update application operation state", logutils.NewLogrusLogger(logutils.NewWithCurrentConfig()), func() error { + _, 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) { return nil } + // kube.RetryUntilSucceed logs failed attempts at "debug" level, but we want to know if this fails. Log a + // warning. + logCtx.Warnf("error patching application with operation state: %v", err) return fmt.Errorf("error patching application with operation state: %w", err) } - log.Infof("updated '%s' operation (phase: %s)", app.QualifiedName(), state.Phase) - if state.Phase.Completed() { - eventInfo := argo.EventInfo{Reason: argo.EventReasonOperationCompleted} - var messages []string - if state.Operation.Sync != nil && len(state.Operation.Sync.Resources) > 0 { - messages = []string{"Partial sync operation"} - } else { - messages = []string{"Sync operation"} - } - if state.SyncResult != nil { - messages = append(messages, "to", state.SyncResult.Revision) - } - if state.Phase.Successful() { - eventInfo.Type = v1.EventTypeNormal - messages = append(messages, "succeeded") - } else { - eventInfo.Type = v1.EventTypeWarning - messages = append(messages, "failed:", state.Message) - } - ctrl.auditLogger.LogAppEvent(app, eventInfo, strings.Join(messages, " ")) - ctrl.metricsServer.IncSync(app, state) - } return nil }) + + logCtx.Infof("updated '%s' operation (phase: %s)", app.QualifiedName(), state.Phase) + if state.Phase.Completed() { + eventInfo := argo.EventInfo{Reason: argo.EventReasonOperationCompleted} + var messages []string + if state.Operation.Sync != nil && len(state.Operation.Sync.Resources) > 0 { + messages = []string{"Partial sync operation"} + } else { + messages = []string{"Sync operation"} + } + if state.SyncResult != nil { + messages = append(messages, "to", state.SyncResult.Revision) + } + if state.Phase.Successful() { + eventInfo.Type = v1.EventTypeNormal + messages = append(messages, "succeeded") + } else { + eventInfo.Type = v1.EventTypeWarning + messages = append(messages, "failed:", state.Message) + } + ctrl.auditLogger.LogAppEvent(app, eventInfo, strings.Join(messages, " "), "") + ctrl.metricsServer.IncSync(app, state) + } +} + +// 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 appKey, shutdown := ctrl.appRefreshQueue.Get() if shutdown { processNext = false @@ -1338,18 +1493,22 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo return } app := origApp.DeepCopy() - logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()}) + logCtx := log.WithFields(log.Fields{ + "application": app.QualifiedName(), + "level": comparisonLevel, + "dest-server": origApp.Spec.Destination.Server, + "dest-name": origApp.Spec.Destination.Name, + "dest-namespace": origApp.Spec.Destination.Namespace, + }) startTime := time.Now() defer func() { reconcileDuration := time.Since(startTime) ctrl.metricsServer.IncReconcile(origApp, reconcileDuration) logCtx.WithFields(log.Fields{ - "time_ms": reconcileDuration.Milliseconds(), - "level": comparisonLevel, - "dest-server": origApp.Spec.Destination.Server, - "dest-name": origApp.Spec.Destination.Name, - "dest-namespace": origApp.Spec.Destination.Namespace, + "time_ms": reconcileDuration.Milliseconds(), + "patch_ms": patchMs.Milliseconds(), + "setop_ms": setOpMs.Milliseconds(), }).Info("Reconciliation completed") }() @@ -1367,7 +1526,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo } } - ctrl.persistAppStatus(origApp, &app.Status) + patchMs = ctrl.persistAppStatus(origApp, &app.Status) return } } @@ -1376,7 +1535,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo if hasErrors { app.Status.Sync.Status = appv1.SyncStatusCodeUnknown app.Status.Health.Status = health.HealthStatusUnknown - ctrl.persistAppStatus(origApp, &app.Status) + patchMs = ctrl.persistAppStatus(origApp, &app.Status) if err := ctrl.cache.SetAppResourcesTree(app.InstanceName(ctrl.namespace), &appv1.ApplicationTree{}); err != nil { log.Warnf("failed to set app resource tree: %v", err) @@ -1420,10 +1579,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()) } @@ -1438,7 +1602,8 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo } if project.Spec.SyncWindows.Matches(app).CanSync(false) { - syncErrCond := ctrl.autoSync(app, compareResult.syncStatus, compareResult.resources) + syncErrCond, opMS := ctrl.autoSync(app, compareResult.syncStatus, compareResult.resources) + setOpMs = opMS if syncErrCond != nil { app.Status.SetConditions( []appv1.ApplicationCondition{*syncErrCond}, @@ -1465,7 +1630,22 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo }) app.Status.SourceType = compareResult.appSourceType app.Status.SourceTypes = compareResult.appSourceTypes - ctrl.persistAppStatus(origApp, &app.Status) + 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 } @@ -1473,15 +1653,23 @@ func resourceStatusKey(res appv1.ResourceStatus) string { return strings.Join([]string{res.Group, res.Kind, res.Namespace, res.Name}, "/") } +func currentSourceEqualsSyncedSource(app *appv1.Application) bool { + if app.Spec.HasMultipleSources() { + return app.Spec.Sources.Equals(app.Status.Sync.ComparedTo.Sources) + } + return app.Spec.Source.Equals(&app.Status.Sync.ComparedTo.Source) +} + // needRefreshAppStatus answers if application status needs to be refreshed. // Returns true if application never been compared, has changed or comparison result has expired. -// Additionally returns whether full refresh was requested or not. +// Additionally, it returns whether full refresh was requested or not. // If full refresh is requested then target and live state should be reconciled, else only live state tree should be updated. func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application, statusRefreshTimeout, statusHardRefreshTimeout time.Duration) (bool, appv1.RefreshType, CompareWith) { logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()}) 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 @@ -1491,18 +1679,16 @@ func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application, refreshType = requestedType reason = fmt.Sprintf("%s refresh requested", refreshType) } else { - if app.Spec.HasMultipleSources() { - if (len(app.Spec.Sources) != len(app.Status.Sync.ComparedTo.Sources)) || !reflect.DeepEqual(app.Spec.Sources, app.Status.Sync.ComparedTo.Sources) { - reason = "atleast one of the spec.sources differs" - compareWith = CompareWithLatestForceResolve - } - } else if !app.Spec.Source.Equals(app.Status.Sync.ComparedTo.Source) { + if !currentSourceEqualsSyncedSource(app) { reason = "spec.source differs" compareWith = CompareWithLatestForceResolve + if app.Spec.HasMultipleSources() { + reason = "at least one of the spec.sources differs" + } } 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() @@ -1514,6 +1700,10 @@ func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application, } } else if !app.Spec.Destination.Equals(app.Status.Sync.ComparedTo.Destination) { reason = "spec.destination differs" + } else if app.HasChangedManagedNamespaceMetadata() { + reason = "spec.syncPolicy.managedNamespaceMetadata differs" + } else if !app.Spec.IgnoreDifferences.Equals(app.Status.Sync.ComparedTo.IgnoreDifferences) { + reason = "spec.ignoreDifferences differs" } else if requested, level := ctrl.isRefreshRequested(app.QualifiedName()); requested { compareWith = level reason = "controller refresh requested" @@ -1560,8 +1750,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 { @@ -1571,15 +1760,15 @@ func (ctrl *ApplicationController) normalizeApplication(orig, app *appv1.Applica } // persistAppStatus persists updates to application status. If no changes were made, it is a no-op -func (ctrl *ApplicationController) persistAppStatus(orig *appv1.Application, newStatus *appv1.ApplicationStatus) { +func (ctrl *ApplicationController) persistAppStatus(orig *appv1.Application, newStatus *appv1.ApplicationStatus) (patchMs time.Duration) { logCtx := log.WithFields(log.Fields{"application": orig.QualifiedName()}) if orig.Status.Sync.Status != newStatus.Sync.Status { message := fmt.Sprintf("Updated sync status: %s -> %s", orig.Status.Sync.Status, newStatus.Sync.Status) - ctrl.auditLogger.LogAppEvent(orig, argo.EventInfo{Reason: argo.EventReasonResourceUpdated, Type: v1.EventTypeNormal}, message) + ctrl.auditLogger.LogAppEvent(orig, argo.EventInfo{Reason: argo.EventReasonResourceUpdated, Type: v1.EventTypeNormal}, message, "") } if orig.Status.Health.Status != newStatus.Health.Status { message := fmt.Sprintf("Updated health status: %s -> %s", orig.Status.Health.Status, newStatus.Health.Status) - ctrl.auditLogger.LogAppEvent(orig, argo.EventInfo{Reason: argo.EventReasonResourceUpdated, Type: v1.EventTypeNormal}, message) + ctrl.auditLogger.LogAppEvent(orig, argo.EventInfo{Reason: argo.EventReasonResourceUpdated, Type: v1.EventTypeNormal}, message, "") } var newAnnotations map[string]string if orig.GetAnnotations() != nil { @@ -1600,36 +1789,41 @@ func (ctrl *ApplicationController) persistAppStatus(orig *appv1.Application, new logCtx.Infof("No status changes. Skipping patch") return } - appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(orig.Namespace) - _, err = appClient.Patch(context.Background(), orig.Name, types.MergePatchType, patch, metav1.PatchOptions{}) + // calculate time for path call + start := time.Now() + defer func() { + patchMs = time.Since(start) + }() + _, 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 { logCtx.Infof("Update successful") } + return patchMs } // autoSync will initiate a sync operation for an application configured with automated sync -func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *appv1.SyncStatus, resources []appv1.ResourceStatus) *appv1.ApplicationCondition { +func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *appv1.SyncStatus, resources []appv1.ResourceStatus) (*appv1.ApplicationCondition, time.Duration) { if app.Spec.SyncPolicy == nil || app.Spec.SyncPolicy.Automated == nil { - return nil + return nil, 0 } logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()}) if app.Operation != nil { logCtx.Infof("Skipping auto-sync: another operation is in progress") - return nil + return nil, 0 } if app.DeletionTimestamp != nil && !app.DeletionTimestamp.IsZero() { logCtx.Infof("Skipping auto-sync: deletion in progress") - return nil + return nil, 0 } // Only perform auto-sync if we detect OutOfSync status. This is to prevent us from attempting // a sync when application is already in a Synced or Unknown state if syncStatus.Status != appv1.SyncStatusCodeOutOfSync { logCtx.Infof("Skipping auto-sync: application status is %s", syncStatus.Status) - return nil + return nil, 0 } if !app.Spec.SyncPolicy.Automated.Prune { @@ -1642,7 +1836,7 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus * } if requirePruneOnly { logCtx.Infof("Skipping auto-sync: need to prune extra resources only but automated prune is disabled") - return nil + return nil, 0 } } @@ -1671,10 +1865,10 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus * if !attemptPhase.Successful() { logCtx.Warnf("Skipping auto-sync: failed previous sync attempt to %s", desiredCommitSHA) message := fmt.Sprintf("Failed sync attempt to %s: %s", desiredCommitSHA, app.Status.OperationState.Message) - return &appv1.ApplicationCondition{Type: appv1.ApplicationConditionSyncError, Message: message} + return &appv1.ApplicationCondition{Type: appv1.ApplicationConditionSyncError, Message: message}, 0 } logCtx.Infof("Skipping auto-sync: most recent sync already to %s", desiredCommitSHA) - return nil + return nil, 0 } else if alreadyAttempted && selfHeal { if shouldSelfHeal, retryAfter := ctrl.shouldSelfHeal(app); shouldSelfHeal { for _, resource := range resources { @@ -1689,7 +1883,7 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus * } else { logCtx.Infof("Skipping auto-sync: already attempted sync to %s with timeout %v (retrying in %v)", desiredCommitSHA, ctrl.selfHealTimeout, retryAfter) ctrl.requestAppRefresh(app.QualifiedName(), CompareWithLatest.Pointer(), &retryAfter) - return nil + return nil, 0 } } @@ -1704,22 +1898,34 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus * if bAllNeedPrune { message := fmt.Sprintf("Skipping sync attempt to %s: auto-sync will wipe out all resources", desiredCommitSHA) logCtx.Warnf(message) - return &appv1.ApplicationCondition{Type: appv1.ApplicationConditionSyncError, Message: message} + return &appv1.ApplicationCondition{Type: appv1.ApplicationConditionSyncError, Message: message}, 0 } } + appIf := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace) - _, err := argo.SetAppOperation(appIf, app.Name, &op) + start := time.Now() + 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()} + 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) + ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonOperationStarted, Type: v1.EventTypeNormal}, message, "") logCtx.Info(message) - return nil + return nil, setOpTime } -// alreadyAttemptedSync returns whether or not the most recent sync was performed against the +// alreadyAttemptedSync returns whether the most recent sync was performed against the // commitSHA and with the same app source config which are currently set in the app func alreadyAttemptedSync(app *appv1.Application, commitSHA string, commitSHAsMS []string, hasMultipleSources bool) (bool, synccommon.OperationPhase) { if app.Status.OperationState == nil || app.Status.OperationState.Operation.Sync == nil || app.Status.OperationState.SyncResult == nil { @@ -1772,26 +1978,43 @@ func (ctrl *ApplicationController) shouldSelfHeal(app *appv1.Application) (bool, return retryAfter <= 0, retryAfter } +// isAppNamespaceAllowed returns whether the application is allowed in the +// namespace it's residing in. +func (ctrl *ApplicationController) isAppNamespaceAllowed(app *appv1.Application) bool { + return app.Namespace == ctrl.namespace || glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, false) +} + func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool { app, ok := obj.(*appv1.Application) if !ok { return false } - 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) - } // Only process given app if it exists in a watched namespace, or in the // control plane's namespace. - if app.Namespace != ctrl.namespace && !glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, false) { + if !ctrl.isAppNamespaceAllowed(app) { return false } - return true + if annotations := app.GetAnnotations(); annotations != nil { + if skipVal, ok := annotations[common.AnnotationKeyAppSkipReconcile]; ok { + logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()}) + if skipReconcile, err := strconv.ParseBool(skipVal); err == nil { + if skipReconcile { + logCtx.Debugf("Skipping Application reconcile based on annotation %s", common.AnnotationKeyAppSkipReconcile) + return false + } + } else { + logCtx.Debugf("Unable to determine if Application should skip reconcile based on annotation %s: %v", common.AnnotationKeyAppSkipReconcile, err) + } + } + } + + cluster, err := ctrl.db.GetCluster(context.Background(), app.Spec.Destination.Server) + if err != nil { + return ctrl.clusterSharding.IsManagedCluster(nil) + } + return ctrl.clusterSharding.IsManagedCluster(cluster) } func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.SharedIndexInformer, applisters.ApplicationLister) { @@ -1816,7 +2039,7 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar } newItems := []appv1.Application{} for _, app := range appList.Items { - if ctrl.namespace == app.Namespace || glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, false) { + if ctrl.isAppNamespaceAllowed(&app) { newItems = append(newItems, app) } } @@ -1833,20 +2056,24 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar cache.NamespaceIndex: func(obj interface{}) ([]string, error) { app, ok := obj.(*appv1.Application) if ok { - // This call to 'ValidateDestination' ensures that the .spec.destination field of all Applications - // returned by the informer/lister will have server field set (if not already set) based on the name. - // (or, if not found, an error app condition) - - // If the server field is not set, set it based on the cluster name; if the cluster name can't be found, - // log an error as an App Condition. - if err := argo.ValidateDestination(context.Background(), &app.Spec.Destination, ctrl.db); err != nil { - ctrl.setAppCondition(app, appv1.ApplicationCondition{Type: appv1.ApplicationConditionInvalidSpecError, Message: err.Error()}) - } - - // If the application is not allowed to use the project, - // log an error. - if _, err := ctrl.getAppProj(app); err != nil { - ctrl.setAppCondition(app, ctrl.projectErrorToCondition(err, app)) + // We only generally work with applications that are in one + // the allowed namespaces. + if ctrl.isAppNamespaceAllowed(app) { + // If the application is not allowed to use the project, + // log an error. + if _, err := ctrl.getAppProj(app); err != nil { + ctrl.setAppCondition(app, ctrl.projectErrorToCondition(err, app)) + } else { + // This call to 'ValidateDestination' ensures that the .spec.destination field of all Applications + // returned by the informer/lister will have server field set (if not already set) based on the name. + // (or, if not found, an error app condition) + + // If the server field is not set, set it based on the cluster name; if the cluster name can't be found, + // log an error as an App Condition. + if err := argo.ValidateDestination(context.Background(), &app.Spec.Destination, ctrl.db); err != nil { + ctrl.setAppCondition(app, appv1.ApplicationCondition{Type: appv1.ApplicationConditionInvalidSpecError, Message: err.Error()}) + } + } } } @@ -1858,7 +2085,11 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar return nil, nil } - proj, err := applisters.NewAppProjectLister(ctrl.projInformer.GetIndexer()).AppProjects(ctrl.namespace).Get(app.Spec.GetProject()) + if !ctrl.isAppNamespaceAllowed(app) { + return nil, nil + } + + proj, err := ctrl.getAppProj(app) if err != nil { return nil, nil } @@ -1870,7 +2101,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) { @@ -1878,8 +2109,12 @@ 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) + } + newApp, newOK := obj.(*appv1.Application) + if err == nil && newOK { + ctrl.clusterSharding.AddApp(newApp) } }, UpdateFunc: func(old, new interface{}) { @@ -1891,15 +2126,27 @@ 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) + ctrl.clusterSharding.UpdateApp(newApp) }, DeleteFunc: func(obj interface{}) { if !ctrl.canProcessApp(obj) { @@ -1909,11 +2156,19 @@ 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) } + delApp, delOK := obj.(*appv1.Application) + if err == nil && delOK { + ctrl.clusterSharding.DeleteApp(delApp) + } }, }, ) + if err != nil { + return nil, nil + } return informer, lister } @@ -1931,7 +2186,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) } @@ -1982,3 +2237,27 @@ func (ctrl *ApplicationController) toAppKey(appName string) string { func (ctrl *ApplicationController) toAppQualifiedName(appName, appNamespace string) string { return fmt.Sprintf("%s/%s", appNamespace, appName) } + +func (ctrl *ApplicationController) getAppList(options metav1.ListOptions) (*appv1.ApplicationList, error) { + watchNamespace := ctrl.namespace + // If we have at least one additional namespace configured, we need to + // watch on them all. + if len(ctrl.applicationNamespaces) > 0 { + watchNamespace = "" + } + + appList, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(watchNamespace).List(context.TODO(), options) + if err != nil { + return nil, err + } + newItems := []appv1.Application{} + for _, app := range appList.Items { + if ctrl.isAppNamespaceAllowed(&app) { + newItems = append(newItems, app) + } + } + appList.Items = newItems + return appList, nil +} + +type ClusterFilterFunction func(c *appv1.Cluster, distributionFunction sharding.DistributionFunction) bool diff --git a/controller/appcontroller_test.go b/controller/appcontroller_test.go index fff4c7f37db5c..33a29bc5ca3f8 100644 --- a/controller/appcontroller_test.go +++ b/controller/appcontroller_test.go @@ -3,21 +3,26 @@ package controller import ( "context" "encoding/json" + "errors" "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/ghodss/yaml" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" corev1 "k8s.io/api/core/v1" @@ -29,10 +34,10 @@ import ( "k8s.io/client-go/kubernetes/fake" kubetesting "k8s.io/client-go/testing" "k8s.io/client-go/tools/cache" + "sigs.k8s.io/yaml" mockstatecache "github.com/argoproj/argo-cd/v2/controller/cache/mocks" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/fake" "github.com/argoproj/argo-cd/v2/reposerver/apiclient" mockrepoclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks" @@ -43,20 +48,39 @@ import ( ) type namespacedResource struct { - argoappv1.ResourceNode + v1alpha1.ResourceNode AppName string } type fakeData struct { apps []runtime.Object manifestResponse *apiclient.ManifestResponse + manifestResponses []*apiclient.ManifestResponse managedLiveObjs map[kube.ResourceKey]*unstructured.Unstructured namespacedResources map[kube.ResourceKey]namespacedResource configMapData map[string]string metricsCacheExpiration time.Duration + applicationNamespaces []string +} + +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) *ApplicationController { +func newFakeController(data *fakeData, repoErr error) *ApplicationController { var clust corev1.Secret err := yaml.Unmarshal([]byte(fakeCluster), &clust) if err != nil { @@ -65,7 +89,23 @@ func newFakeController(data *fakeData) *ApplicationController { // Mock out call to GenerateManifest mockRepoClient := mockrepoclient.RepoServerServiceClient{} - mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(data.manifestResponse, nil) + + if len(data.manifestResponses) > 0 { + for _, response := range data.manifestResponses { + 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 { + 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} secret := corev1.Secret{ @@ -90,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, @@ -104,15 +144,25 @@ func newFakeController(data *fakeData) *ApplicationController { kubectl, time.Minute, time.Hour, + time.Second, time.Minute, + time.Second*10, common.DefaultPortArgoCDMetrics, data.metricsCacheExpiration, []string{}, 0, true, nil, - []string{}, + 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) } @@ -131,7 +181,7 @@ func newFakeController(data *fakeData) *ApplicationController { mockStateCache.On("IsNamespaced", mock.Anything, mock.Anything).Return(true, nil) mockStateCache.On("GetManagedLiveObjs", mock.Anything, mock.Anything).Return(data.managedLiveObjs, nil) mockStateCache.On("GetVersionsInfo", mock.Anything).Return("v1.2.3", nil, nil) - response := make(map[kube.ResourceKey]argoappv1.ResourceNode) + response := make(map[kube.ResourceKey]v1alpha1.ResourceNode) for k, v := range data.namespacedResources { response[k] = v.ResourceNode } @@ -140,12 +190,12 @@ func newFakeController(data *fakeData) *ApplicationController { mockStateCache.On("GetClusterCache", mock.Anything).Return(&clusterCacheMock, nil) mockStateCache.On("IterateHierarchy", mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) { key := args[1].(kube.ResourceKey) - action := args[2].(func(child argoappv1.ResourceNode, appName string) bool) + action := args[2].(func(child v1alpha1.ResourceNode, appName string) bool) appName := "" if res, ok := data.namespacedResources[key]; ok { appName = res.AppName } - _ = action(argoappv1.ResourceNode{ResourceRef: argoappv1.ResourceRef{Kind: key.Kind, Group: key.Group, Namespace: key.Namespace, Name: key.Name}}, appName) + _ = action(v1alpha1.ResourceNode{ResourceRef: v1alpha1.ResourceRef{Kind: key.Kind, Group: key.Group, Namespace: key.Namespace, Name: key.Name}}, appName) }).Return(nil) return ctrl } @@ -167,7 +217,6 @@ metadata: namespace: ` + test.FakeArgoCDNamespace + ` type: Opaque ` - var fakeApp = ` apiVersion: argoproj.io/v1alpha1 kind: Application @@ -209,6 +258,64 @@ status: repoURL: https://github.com/argoproj/argocd-example-apps.git ` +var fakeMultiSourceApp = ` +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + uid: "123" + name: my-app + namespace: ` + test.FakeArgoCDNamespace + ` +spec: + destination: + namespace: ` + test.FakeDestNamespace + ` + server: https://localhost:6443 + project: default + sources: + - path: some/path + helm: + valueFiles: + - $values_test/values.yaml + repoURL: https://github.com/argoproj/argocd-example-apps.git + - path: some/other/path + repoURL: https://github.com/argoproj/argocd-example-apps-fake.git + - ref: values_test + repoURL: https://github.com/argoproj/argocd-example-apps-fake-ref.git + syncPolicy: + automated: {} +status: + operationState: + finishedAt: 2018-09-21T23:50:29Z + message: successfully synced + operation: + sync: + revisions: + - HEAD + - HEAD + - HEAD + phase: Succeeded + startedAt: 2018-09-21T23:50:25Z + syncResult: + resources: + - kind: RoleBinding + message: |- + rolebinding.rbac.authorization.k8s.io/always-outofsync reconciled + rolebinding.rbac.authorization.k8s.io/always-outofsync configured + name: always-outofsync + namespace: default + status: Synced + revisions: + - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + - cccccccccccccccccccccccccccccccccccccccc + sources: + - path: some/path + repoURL: https://github.com/argoproj/argocd-example-apps.git + - path: some/other/path + repoURL: https://github.com/argoproj/argocd-example-apps-fake.git + - path: some/other/path + repoURL: https://github.com/argoproj/argocd-example-apps-fake-ref.git +` + var fakeAppWithDestName = ` apiVersion: argoproj.io/v1alpha1 kind: Application @@ -259,20 +366,56 @@ metadata: data: ` -func newFakeApp() *argoappv1.Application { +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) } -func newFakeAppWithDestMismatch() *argoappv1.Application { +func newFakeMultiSourceApp() *v1alpha1.Application { + return createFakeApp(fakeMultiSourceApp) +} + +func newFakeAppWithDestMismatch() *v1alpha1.Application { return createFakeApp(fakeAppWithDestMismatch) } -func newFakeAppWithDestName() *argoappv1.Application { +func newFakeAppWithDestName() *v1alpha1.Application { return createFakeApp(fakeAppWithDestName) } -func createFakeApp(testApp string) *argoappv1.Application { - var app argoappv1.Application +func createFakeApp(testApp string) *v1alpha1.Application { + var app v1alpha1.Application err := yaml.Unmarshal([]byte(testApp), &app) if err != nil { panic(err) @@ -289,14 +432,23 @@ 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}}) - syncStatus := argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeOutOfSync, + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) + syncStatus := v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", } - cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: argoappv1.SyncStatusCodeOutOfSync}}) + cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: v1alpha1.SyncStatusCodeOutOfSync}}) assert.Nil(t, cond) app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(context.Background(), "my-app", metav1.GetOptions{}) assert.NoError(t, err) @@ -308,12 +460,12 @@ 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}}) - syncStatus := argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeOutOfSync, + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) + syncStatus := v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", } - cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{}) + cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{}) assert.NotNil(t, cond) } @@ -321,12 +473,12 @@ 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}}) - syncStatus := argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeOutOfSync, + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) + syncStatus := v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", } - cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{}) + cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{}) assert.Nil(t, cond) } @@ -335,12 +487,12 @@ 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}}) - syncStatus := argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeOutOfSync, + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) + syncStatus := v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", } - cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{}) + cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{}) assert.Nil(t, cond) app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(context.Background(), "my-app", metav1.GetOptions{}) assert.NoError(t, err) @@ -350,12 +502,12 @@ 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}}) - syncStatus := argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeSynced, + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) + syncStatus := v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", } - cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{}) + cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{}) assert.Nil(t, cond) app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(context.Background(), "my-app", metav1.GetOptions{}) assert.NoError(t, err) @@ -366,12 +518,12 @@ 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}}) - syncStatus := argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeOutOfSync, + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) + syncStatus := v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", } - cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{}) + cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{}) assert.Nil(t, cond) app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(context.Background(), "my-app", metav1.GetOptions{}) assert.NoError(t, err) @@ -383,12 +535,12 @@ func TestSkipAutoSync(t *testing.T) { app := newFakeApp() now := metav1.Now() app.DeletionTimestamp = &now - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) - syncStatus := argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeOutOfSync, + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) + syncStatus := v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", } - cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{}) + cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{}) assert.Nil(t, cond) app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(context.Background(), "my-app", metav1.GetOptions{}) assert.NoError(t, err) @@ -399,22 +551,22 @@ func TestSkipAutoSync(t *testing.T) { // Set current to 'aaaaa', desired to 'bbbbb' and add 'bbbbb' to failure history t.Run("PreviousSyncAttemptFailed", func(t *testing.T) { app := newFakeApp() - app.Status.OperationState = &argoappv1.OperationState{ - Operation: argoappv1.Operation{ - Sync: &argoappv1.SyncOperation{}, + app.Status.OperationState = &v1alpha1.OperationState{ + Operation: v1alpha1.Operation{ + Sync: &v1alpha1.SyncOperation{}, }, Phase: synccommon.OperationFailed, - SyncResult: &argoappv1.SyncOperationResult{ + SyncResult: &v1alpha1.SyncOperationResult{ Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", Source: *app.Spec.Source.DeepCopy(), }, } - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) - syncStatus := argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeOutOfSync, + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) + syncStatus := v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", } - cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: argoappv1.SyncStatusCodeOutOfSync}}) + cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: v1alpha1.SyncStatusCodeOutOfSync}}) assert.NotNil(t, cond) app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(context.Background(), "my-app", metav1.GetOptions{}) assert.NoError(t, err) @@ -423,13 +575,13 @@ func TestSkipAutoSync(t *testing.T) { t.Run("NeedsToPruneResourcesOnlyButAutomatedPruneDisabled", func(t *testing.T) { app := newFakeApp() - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) - syncStatus := argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeOutOfSync, + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) + syncStatus := v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", } - cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{ - {Name: "guestbook", Kind: kube.DeploymentKind, Status: argoappv1.SyncStatusCodeOutOfSync, RequiresPruning: true}, + cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{ + {Name: "guestbook", Kind: kube.DeploymentKind, Status: v1alpha1.SyncStatusCodeOutOfSync, RequiresPruning: true}, }) assert.Nil(t, cond) app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(context.Background(), "my-app", metav1.GetOptions{}) @@ -441,32 +593,32 @@ func TestSkipAutoSync(t *testing.T) { // TestAutoSyncIndicateError verifies we skip auto-sync and return error condition if previous sync failed func TestAutoSyncIndicateError(t *testing.T) { app := newFakeApp() - app.Spec.Source.Helm = &argoappv1.ApplicationSourceHelm{ - Parameters: []argoappv1.HelmParameter{ + app.Spec.Source.Helm = &v1alpha1.ApplicationSourceHelm{ + Parameters: []v1alpha1.HelmParameter{ { Name: "a", Value: "1", }, }, } - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) - syncStatus := argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeOutOfSync, + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) + syncStatus := v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", } - app.Status.OperationState = &argoappv1.OperationState{ - Operation: argoappv1.Operation{ - Sync: &argoappv1.SyncOperation{ + app.Status.OperationState = &v1alpha1.OperationState{ + Operation: v1alpha1.Operation{ + Sync: &v1alpha1.SyncOperation{ Source: app.Spec.Source.DeepCopy(), }, }, Phase: synccommon.OperationFailed, - SyncResult: &argoappv1.SyncOperationResult{ + SyncResult: &v1alpha1.SyncOperationResult{ Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Source: *app.Spec.Source.DeepCopy(), }, } - cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: argoappv1.SyncStatusCodeOutOfSync}}) + cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: v1alpha1.SyncStatusCodeOutOfSync}}) assert.NotNil(t, cond) app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(context.Background(), "my-app", metav1.GetOptions{}) assert.NoError(t, err) @@ -476,25 +628,25 @@ func TestAutoSyncIndicateError(t *testing.T) { // TestAutoSyncParameterOverrides verifies we auto-sync if revision is same but parameter overrides are different func TestAutoSyncParameterOverrides(t *testing.T) { app := newFakeApp() - app.Spec.Source.Helm = &argoappv1.ApplicationSourceHelm{ - Parameters: []argoappv1.HelmParameter{ + app.Spec.Source.Helm = &v1alpha1.ApplicationSourceHelm{ + Parameters: []v1alpha1.HelmParameter{ { Name: "a", Value: "1", }, }, } - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) - syncStatus := argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeOutOfSync, + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) + syncStatus := v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", } - app.Status.OperationState = &argoappv1.OperationState{ - Operation: argoappv1.Operation{ - Sync: &argoappv1.SyncOperation{ - Source: &argoappv1.ApplicationSource{ - Helm: &argoappv1.ApplicationSourceHelm{ - Parameters: []argoappv1.HelmParameter{ + app.Status.OperationState = &v1alpha1.OperationState{ + Operation: v1alpha1.Operation{ + Sync: &v1alpha1.SyncOperation{ + Source: &v1alpha1.ApplicationSource{ + Helm: &v1alpha1.ApplicationSourceHelm{ + Parameters: []v1alpha1.HelmParameter{ { Name: "a", Value: "2", // this value changed @@ -505,11 +657,11 @@ func TestAutoSyncParameterOverrides(t *testing.T) { }, }, Phase: synccommon.OperationFailed, - SyncResult: &argoappv1.SyncOperationResult{ + SyncResult: &v1alpha1.SyncOperationResult{ Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, } - cond := ctrl.autoSync(app, &syncStatus, []argoappv1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: argoappv1.SyncStatusCodeOutOfSync}}) + cond, _ := ctrl.autoSync(app, &syncStatus, []v1alpha1.ResourceStatus{{Name: "guestbook", Kind: kube.DeploymentKind, Status: v1alpha1.SyncStatusCodeOutOfSync}}) assert.Nil(t, cond) app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(test.FakeArgoCDNamespace).Get(context.Background(), "my-app", metav1.GetOptions{}) assert.NoError(t, err) @@ -518,14 +670,14 @@ func TestAutoSyncParameterOverrides(t *testing.T) { // TestFinalizeAppDeletion verifies application deletion func TestFinalizeAppDeletion(t *testing.T) { - defaultProj := argoappv1.AppProject{ + defaultProj := v1alpha1.AppProject{ ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: test.FakeArgoCDNamespace, }, - Spec: argoappv1.AppProjectSpec{ + Spec: v1alpha1.AppProjectSpec{ SourceRepos: []string{"*"}, - Destinations: []argoappv1.ApplicationDestination{ + Destinations: []v1alpha1.ApplicationDestination{ { Server: "*", Namespace: "*", @@ -537,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] @@ -552,10 +704,10 @@ 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) ([]*argoappv1.Cluster, error) { - return []*argoappv1.Cluster{}, nil + err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { + return []*v1alpha1.Cluster{}, nil }) assert.NoError(t, err) assert.True(t, patched) @@ -564,14 +716,14 @@ func TestFinalizeAppDeletion(t *testing.T) { // Ensure any stray resources irregularly labeled with instance label of app are not deleted upon deleting, // when app project restriction is in place t.Run("ProjectRestrictionEnforced", func(*testing.T) { - restrictedProj := argoappv1.AppProject{ + restrictedProj := v1alpha1.AppProject{ ObjectMeta: metav1.ObjectMeta{ Name: "restricted", Namespace: test.FakeArgoCDNamespace, }, - Spec: argoappv1.AppProjectSpec{ + Spec: v1alpha1.AppProjectSpec{ SourceRepos: []string{"*"}, - Destinations: []argoappv1.ApplicationDestination{ + Destinations: []v1alpha1.ApplicationDestination{ { Server: "*", Namespace: "my-app", @@ -580,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) @@ -591,7 +744,7 @@ func TestFinalizeAppDeletion(t *testing.T) { kube.GetResourceKey(appObj): appObj, kube.GetResourceKey(strayObj): strayObj, }, - }) + }, nil) patched := false fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) @@ -602,10 +755,10 @@ 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) ([]*argoappv1.Cluster, error) { - return []*argoappv1.Cluster{}, nil + err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { + return []*v1alpha1.Cluster{}, nil }) assert.NoError(t, err) assert.True(t, patched) @@ -615,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] @@ -636,10 +791,10 @@ 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) ([]*argoappv1.Cluster, error) { - return []*argoappv1.Cluster{}, nil + err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { + return []*v1alpha1.Cluster{}, nil }) assert.NoError(t, err) assert.True(t, patched) @@ -651,11 +806,11 @@ func TestFinalizeAppDeletion(t *testing.T) { appTemplate := newFakeAppWithDestName() - testShouldDelete := func(app *argoappv1.Application) { + testShouldDelete := func(app *v1alpha1.Application) { 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] @@ -663,8 +818,8 @@ 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) ([]*argoappv1.Cluster, error) { - return []*argoappv1.Cluster{}, nil + err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { + return []*v1alpha1.Cluster{}, nil }) assert.NoError(t, err) } @@ -684,18 +839,121 @@ 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 func TestNormalizeApplication(t *testing.T) { - defaultProj := argoappv1.AppProject{ + defaultProj := v1alpha1.AppProject{ ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: test.FakeArgoCDNamespace, }, - Spec: argoappv1.AppProjectSpec{ + Spec: v1alpha1.AppProjectSpec{ SourceRepos: []string{"*"}, - Destinations: []argoappv1.ApplicationDestination{ + Destinations: []v1alpha1.ApplicationDestination{ { Server: "*", Namespace: "*", @@ -705,7 +963,7 @@ func TestNormalizeApplication(t *testing.T) { } app := newFakeApp() app.Spec.Project = "" - app.Spec.Source.Kustomize = &argoappv1.ApplicationSourceKustomize{NamePrefix: "foo-"} + app.Spec.Source.Kustomize = &v1alpha1.ApplicationSourceKustomize{NamePrefix: "foo-"} data := fakeData{ apps: []runtime.Object{app, &defaultProj}, manifestResponse: &apiclient.ManifestResponse{ @@ -719,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 @@ -731,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) @@ -741,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 @@ -753,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) @@ -763,10 +1021,10 @@ func TestNormalizeApplication(t *testing.T) { func TestHandleAppUpdated(t *testing.T) { app := newFakeApp() app.Spec.Destination.Namespace = test.FakeArgoCDNamespace - app.Spec.Destination.Server = argoappv1.KubernetesInternalAPIServerAddr + 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()) @@ -783,17 +1041,17 @@ func TestHandleOrphanedResourceUpdated(t *testing.T) { app1 := newFakeApp() app1.Name = "app1" app1.Spec.Destination.Namespace = test.FakeArgoCDNamespace - app1.Spec.Destination.Server = argoappv1.KubernetesInternalAPIServerAddr + app1.Spec.Destination.Server = v1alpha1.KubernetesInternalAPIServerAddr app2 := newFakeApp() app2.Name = "app2" app2.Spec.Destination.Namespace = test.FakeArgoCDNamespace - app2.Spec.Destination.Server = argoappv1.KubernetesInternalAPIServerAddr + app2.Spec.Destination.Server = v1alpha1.KubernetesInternalAPIServerAddr proj := defaultProj.DeepCopy() - proj.Spec.OrphanedResources = &argoappv1.OrphanedResourcesMonitorSettings{} + 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}) @@ -809,16 +1067,16 @@ func TestHandleOrphanedResourceUpdated(t *testing.T) { func TestGetResourceTree_HasOrphanedResources(t *testing.T) { app := newFakeApp() proj := defaultProj.DeepCopy() - proj.Spec.OrphanedResources = &argoappv1.OrphanedResourcesMonitorSettings{} + proj.Spec.OrphanedResources = &v1alpha1.OrphanedResourcesMonitorSettings{} - managedDeploy := argoappv1.ResourceNode{ - ResourceRef: argoappv1.ResourceRef{Group: "apps", Kind: "Deployment", Namespace: "default", Name: "nginx-deployment", Version: "v1"}, + managedDeploy := v1alpha1.ResourceNode{ + ResourceRef: v1alpha1.ResourceRef{Group: "apps", Kind: "Deployment", Namespace: "default", Name: "nginx-deployment", Version: "v1"}, } - orphanedDeploy1 := argoappv1.ResourceNode{ - ResourceRef: argoappv1.ResourceRef{Group: "apps", Kind: "Deployment", Namespace: "default", Name: "deploy1"}, + orphanedDeploy1 := v1alpha1.ResourceNode{ + ResourceRef: v1alpha1.ResourceRef{Group: "apps", Kind: "Deployment", Namespace: "default", Name: "deploy1"}, } - orphanedDeploy2 := argoappv1.ResourceNode{ - ResourceRef: argoappv1.ResourceRef{Group: "apps", Kind: "Deployment", Namespace: "default", Name: "deploy2"}, + orphanedDeploy2 := v1alpha1.ResourceNode{ + ResourceRef: v1alpha1.ResourceRef{Group: "apps", Kind: "Deployment", Namespace: "default", Name: "deploy2"}, } ctrl := newFakeController(&fakeData{ @@ -828,8 +1086,8 @@ func TestGetResourceTree_HasOrphanedResources(t *testing.T) { kube.NewResourceKey("apps", "Deployment", "default", "deploy1"): {ResourceNode: orphanedDeploy1}, kube.NewResourceKey("apps", "Deployment", "default", "deploy2"): {ResourceNode: orphanedDeploy2}, }, - }) - tree, err := ctrl.getResourceTree(app, []*argoappv1.ResourceDiff{{ + }, nil) + tree, err := ctrl.getResourceTree(app, []*v1alpha1.ResourceDiff{{ Namespace: "default", Name: "nginx-deployment", Kind: "Deployment", @@ -839,131 +1097,300 @@ func TestGetResourceTree_HasOrphanedResources(t *testing.T) { }}) assert.NoError(t, err) - assert.Equal(t, tree.Nodes, []argoappv1.ResourceNode{managedDeploy}) - assert.Equal(t, tree.OrphanedNodes, []argoappv1.ResourceNode{orphanedDeploy1, orphanedDeploy2}) + assert.Equal(t, tree.Nodes, []v1alpha1.ResourceNode{managedDeploy}) + assert.Equal(t, tree.OrphanedNodes, []v1alpha1.ResourceNode{orphanedDeploy1, orphanedDeploy2}) } 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(), &argoappv1.OperationState{Phase: synccommon.OperationSucceeded}) + ctrl.setOperationState(newFakeApp(), &v1alpha1.OperationState{Phase: synccommon.OperationSucceeded}) assert.True(t, patched) } -func TestNeedRefreshAppStatus(t *testing.T) { - ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}) +type logHook struct { + entries []logrus.Entry +} - app := newFakeApp() - now := metav1.Now() - app.Status.ReconciledAt = &now - app.Status.Sync = argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeSynced, - ComparedTo: argoappv1.ComparedTo{ - Source: app.Spec.GetSource(), - Destination: app.Spec.Destination, +func (h *logHook) Levels() []logrus.Level { + return []logrus.Level{logrus.WarnLevel} +} + +func (h *logHook) Fire(entry *logrus.Entry) error { + h.entries = append(h.entries, *entry) + return nil +} + +func TestSetOperationStateLogRetries(t *testing.T) { + hook := logHook{} + logrus.AddHook(&hook) + t.Cleanup(func() { + logrus.StandardLogger().ReplaceHooks(logrus.LevelHooks{}) + }) + 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, &v1alpha1.Application{}, errors.New("fake error") + } + return true, &v1alpha1.Application{}, nil + }) + ctrl.setOperationState(newFakeApp(), &v1alpha1.OperationState{Phase: synccommon.OperationSucceeded}) + assert.True(t, patched) + assert.Contains(t, hook.entries[0].Message, "fake error") +} + +func TestNeedRefreshAppStatus(t *testing.T) { + testCases := []struct { + name string + app *v1alpha1.Application + }{ + { + name: "single-source app", + app: newFakeApp(), + }, + { + name: "multi-source app", + app: newFakeMultiSourceApp(), }, } - // no need to refresh just reconciled application - needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) - assert.False(t, needRefresh) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + app := tc.app + now := metav1.Now() + app.Status.ReconciledAt = &now + + app.Status.Sync = v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, + ComparedTo: v1alpha1.ComparedTo{ + Destination: app.Spec.Destination, + IgnoreDifferences: app.Spec.IgnoreDifferences, + }, + } - // refresh app using the 'deepest' requested comparison level - ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil) - ctrl.requestAppRefresh(app.Name, ComparisonWithNothing.Pointer(), nil) + if app.Spec.HasMultipleSources() { + app.Status.Sync.ComparedTo.Sources = app.Spec.Sources + } else { + app.Status.Sync.ComparedTo.Source = app.Spec.GetSource() + } - needRefresh, refreshType, compareWith := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) - assert.True(t, needRefresh) - assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType) - assert.Equal(t, CompareWithRecent, compareWith) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) - // refresh application which status is not reconciled using latest commit - app.Status.Sync = argoappv1.SyncStatus{Status: argoappv1.SyncStatusCodeUnknown} + t.Run("no need to refresh just reconciled application", func(t *testing.T) { + needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.False(t, needRefresh) + }) - needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) - assert.True(t, needRefresh) - assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType) - assert.Equal(t, CompareWithLatestForceResolve, compareWith) + t.Run("requested refresh is respected", func(t *testing.T) { + needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.False(t, needRefresh) - { - // refresh app using the 'latest' level if comparison expired - app := app.DeepCopy() - ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil) - reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour)) - app.Status.ReconciledAt = &reconciledAt - needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Minute, 2*time.Hour) - assert.True(t, needRefresh) - assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType) - assert.Equal(t, CompareWithLatestForceResolve, compareWith) - } + // use a one-off controller so other tests don't have a manual refresh request + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) - { - // refresh app using the 'latest' level if comparison expired for hard refresh - app := app.DeepCopy() - app.Status.Sync = argoappv1.SyncStatus{ - Status: argoappv1.SyncStatusCodeSynced, - ComparedTo: argoappv1.ComparedTo{ - Source: app.Spec.GetSource(), - Destination: app.Spec.Destination, - }, - } - ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil) - reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour)) - app.Status.ReconciledAt = &reconciledAt - needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 2*time.Hour, 1*time.Minute) - assert.True(t, needRefresh) - assert.Equal(t, argoappv1.RefreshTypeHard, refreshType) - assert.Equal(t, CompareWithLatest, compareWith) + // refresh app using the 'deepest' requested comparison level + ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil) + ctrl.requestAppRefresh(app.Name, ComparisonWithNothing.Pointer(), nil) + + needRefresh, refreshType, compareWith := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.True(t, needRefresh) + assert.Equal(t, v1alpha1.RefreshTypeNormal, refreshType) + assert.Equal(t, CompareWithRecent, compareWith) + }) + + t.Run("refresh application which status is not reconciled using latest commit", func(t *testing.T) { + app := app.DeepCopy() + needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.False(t, needRefresh) + app.Status.Sync = v1alpha1.SyncStatus{Status: v1alpha1.SyncStatusCodeUnknown} + + needRefresh, refreshType, compareWith := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.True(t, needRefresh) + assert.Equal(t, v1alpha1.RefreshTypeNormal, refreshType) + assert.Equal(t, CompareWithLatestForceResolve, compareWith) + }) + + t.Run("refresh app using the 'latest' level if comparison expired", func(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{}}, nil) + + needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.False(t, needRefresh) + + ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil) + reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour)) + app.Status.ReconciledAt = &reconciledAt + needRefresh, refreshType, compareWith := ctrl.needRefreshAppStatus(app, 1*time.Minute, 2*time.Hour) + assert.True(t, needRefresh) + assert.Equal(t, v1alpha1.RefreshTypeNormal, refreshType) + assert.Equal(t, CompareWithLatest, compareWith) + }) + + t.Run("refresh app using the 'latest' level if comparison expired for hard refresh", func(t *testing.T) { + app := app.DeepCopy() + app.Status.Sync = v1alpha1.SyncStatus{ + Status: v1alpha1.SyncStatusCodeSynced, + ComparedTo: v1alpha1.ComparedTo{ + Destination: app.Spec.Destination, + IgnoreDifferences: app.Spec.IgnoreDifferences, + }, + } + if app.Spec.HasMultipleSources() { + app.Status.Sync.ComparedTo.Sources = app.Spec.Sources + } else { + app.Status.Sync.ComparedTo.Source = app.Spec.GetSource() + } + + // use a one-off controller so other tests don't have a manual refresh request + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) + + needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.False(t, needRefresh) + ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil) + reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour)) + app.Status.ReconciledAt = &reconciledAt + needRefresh, refreshType, compareWith := ctrl.needRefreshAppStatus(app, 2*time.Hour, 1*time.Minute) + assert.True(t, needRefresh) + assert.Equal(t, v1alpha1.RefreshTypeHard, refreshType) + assert.Equal(t, CompareWithLatest, compareWith) + }) + + t.Run("execute hard refresh if app has refresh annotation", func(t *testing.T) { + app := app.DeepCopy() + needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.False(t, needRefresh) + reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour)) + app.Status.ReconciledAt = &reconciledAt + app.Annotations = map[string]string{ + v1alpha1.AnnotationKeyRefresh: string(v1alpha1.RefreshTypeHard), + } + needRefresh, refreshType, compareWith := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.True(t, needRefresh) + assert.Equal(t, v1alpha1.RefreshTypeHard, refreshType) + assert.Equal(t, CompareWithLatestForceResolve, compareWith) + }) + + t.Run("ensure that CompareWithLatest level is used if application source has changed", func(t *testing.T) { + app := app.DeepCopy() + needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.False(t, needRefresh) + // sample app source change + if app.Spec.HasMultipleSources() { + app.Spec.Sources[0].Helm = &v1alpha1.ApplicationSourceHelm{ + Parameters: []v1alpha1.HelmParameter{{ + Name: "foo", + Value: "bar", + }}, + } + } else { + app.Spec.Source.Helm = &v1alpha1.ApplicationSourceHelm{ + Parameters: []v1alpha1.HelmParameter{{ + Name: "foo", + Value: "bar", + }}, + } + } + + needRefresh, refreshType, compareWith := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.True(t, needRefresh) + assert.Equal(t, v1alpha1.RefreshTypeNormal, refreshType) + assert.Equal(t, CompareWithLatestForceResolve, compareWith) + }) + + t.Run("ensure that CompareWithLatest level is used if ignored differences change", func(t *testing.T) { + app := app.DeepCopy() + needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.False(t, needRefresh) + + app.Spec.IgnoreDifferences = []v1alpha1.ResourceIgnoreDifferences{ + { + Group: "apps", + Kind: "Deployment", + JSONPointers: []string{ + "/spec/template/spec/containers/0/image", + }, + }, + } + + needRefresh, refreshType, compareWith := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) + assert.True(t, needRefresh) + assert.Equal(t, v1alpha1.RefreshTypeNormal, refreshType) + assert.Equal(t, CompareWithLatest, compareWith) + }) + }) } +} - { - app := app.DeepCopy() - // execute hard refresh if app has refresh annotation - reconciledAt := metav1.NewTime(time.Now().UTC().Add(-1 * time.Hour)) - app.Status.ReconciledAt = &reconciledAt - app.Annotations = map[string]string{ - v1alpha1.AnnotationKeyRefresh: string(argoappv1.RefreshTypeHard), - } - needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) - assert.True(t, needRefresh) - assert.Equal(t, argoappv1.RefreshTypeHard, refreshType) - assert.Equal(t, CompareWithLatestForceResolve, compareWith) +func TestUpdatedManagedNamespaceMetadata(t *testing.T) { + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) + app := newFakeApp() + app.Spec.SyncPolicy.ManagedNamespaceMetadata = &v1alpha1.ManagedNamespaceMetadata{ + Labels: map[string]string{ + "foo": "bar", + }, + Annotations: map[string]string{ + "foo": "bar", + }, } + app.Status.Sync.ComparedTo.Source = app.Spec.GetSource() + app.Status.Sync.ComparedTo.Destination = app.Spec.Destination - { - app := app.DeepCopy() - // ensure that CompareWithLatest level is used if application source has changed - ctrl.requestAppRefresh(app.Name, ComparisonWithNothing.Pointer(), nil) - // sample app source change - app.Spec.Source.Helm = &argoappv1.ApplicationSourceHelm{ - Parameters: []argoappv1.HelmParameter{{ - Name: "foo", - Value: "bar", - }}, - } + // Ensure that hard/soft refresh isn't triggered due to reconciledAt being expired + reconciledAt := metav1.NewTime(time.Now().UTC().Add(15 * time.Minute)) + app.Status.ReconciledAt = &reconciledAt + needRefresh, refreshType, compareWith := ctrl.needRefreshAppStatus(app, 30*time.Minute, 2*time.Hour) - needRefresh, refreshType, compareWith = ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) - assert.True(t, needRefresh) - assert.Equal(t, argoappv1.RefreshTypeNormal, refreshType) - assert.Equal(t, CompareWithLatestForceResolve, compareWith) + assert.True(t, needRefresh) + assert.Equal(t, v1alpha1.RefreshTypeNormal, refreshType) + assert.Equal(t, CompareWithLatest, compareWith) +} + +func TestUnchangedManagedNamespaceMetadata(t *testing.T) { + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) + app := newFakeApp() + app.Spec.SyncPolicy.ManagedNamespaceMetadata = &v1alpha1.ManagedNamespaceMetadata{ + Labels: map[string]string{ + "foo": "bar", + }, + Annotations: map[string]string{ + "foo": "bar", + }, } + app.Status.Sync.ComparedTo.Source = app.Spec.GetSource() + app.Status.Sync.ComparedTo.Destination = app.Spec.Destination + app.Status.OperationState.SyncResult.ManagedNamespaceMetadata = app.Spec.SyncPolicy.ManagedNamespaceMetadata + + // Ensure that hard/soft refresh isn't triggered due to reconciledAt being expired + reconciledAt := metav1.NewTime(time.Now().UTC().Add(15 * time.Minute)) + app.Status.ReconciledAt = &reconciledAt + needRefresh, refreshType, compareWith := ctrl.needRefreshAppStatus(app, 30*time.Minute, 2*time.Hour) + + assert.False(t, needRefresh) + assert.Equal(t, v1alpha1.RefreshTypeNormal, refreshType) + assert.Equal(t, CompareWithLatest, compareWith) } func TestRefreshAppConditions(t *testing.T) { - defaultProj := argoappv1.AppProject{ + defaultProj := v1alpha1.AppProject{ ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: test.FakeArgoCDNamespace, }, - Spec: argoappv1.AppProjectSpec{ + Spec: v1alpha1.AppProjectSpec{ SourceRepos: []string{"*"}, - Destinations: []argoappv1.ApplicationDestination{ + Destinations: []v1alpha1.ApplicationDestination{ { Server: "*", Namespace: "*", @@ -974,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) @@ -983,27 +1410,27 @@ func TestRefreshAppConditions(t *testing.T) { t.Run("PreserveExistingWarningCondition", func(t *testing.T) { app := newFakeApp() - app.Status.SetConditions([]argoappv1.ApplicationCondition{{Type: argoappv1.ApplicationConditionExcludedResourceWarning}}, nil) + 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) assert.Len(t, app.Status.Conditions, 1) - assert.Equal(t, argoappv1.ApplicationConditionExcludedResourceWarning, app.Status.Conditions[0].Type) + assert.Equal(t, v1alpha1.ApplicationConditionExcludedResourceWarning, app.Status.Conditions[0].Type) }) t.Run("ReplacesSpecErrorCondition", func(t *testing.T) { app := newFakeApp() app.Spec.Project = "wrong project" - app.Status.SetConditions([]argoappv1.ApplicationCondition{{Type: argoappv1.ApplicationConditionInvalidSpecError, Message: "old message"}}, nil) + 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) assert.Len(t, app.Status.Conditions, 1) - assert.Equal(t, argoappv1.ApplicationConditionInvalidSpecError, app.Status.Conditions[0].Type) + assert.Equal(t, v1alpha1.ApplicationConditionInvalidSpecError, app.Status.Conditions[0].Type) assert.Equal(t, "Application referencing project wrong project which does not exist", app.Status.Conditions[0].Message) }) } @@ -1011,8 +1438,8 @@ func TestRefreshAppConditions(t *testing.T) { func TestUpdateReconciledAt(t *testing.T) { app := newFakeApp() reconciledAt := metav1.NewTime(time.Now().Add(-1 * time.Second)) - app.Status = argoappv1.ApplicationStatus{ReconciledAt: &reconciledAt} - app.Status.Sync = argoappv1.SyncStatus{ComparedTo: argoappv1.ComparedTo{Source: app.Spec.GetSource(), Destination: app.Spec.Destination}} + app.Status = v1alpha1.ApplicationStatus{ReconciledAt: &reconciledAt} + app.Status.Sync = v1alpha1.SyncStatus{ComparedTo: v1alpha1.ComparedTo{Source: app.Spec.GetSource(), Destination: app.Spec.Destination, IgnoreDifferences: app.Spec.IgnoreDifferences}} ctrl := newFakeController(&fakeData{ apps: []runtime.Object{app, &defaultProj}, manifestResponse: &apiclient.ManifestResponse{ @@ -1022,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 @@ -1031,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() @@ -1052,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() @@ -1080,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() @@ -1090,22 +1517,22 @@ func TestProjectErrorToCondition(t *testing.T) { obj, ok, err := ctrl.appInformer.GetIndexer().GetByKey(key) assert.True(t, ok) assert.NoError(t, err) - updatedApp := obj.(*argoappv1.Application) - assert.Equal(t, argoappv1.ApplicationConditionInvalidSpecError, updatedApp.Status.Conditions[0].Type) + updatedApp := obj.(*v1alpha1.Application) + assert.Equal(t, v1alpha1.ApplicationConditionInvalidSpecError, updatedApp.Status.Conditions[0].Type) assert.Equal(t, "Application referencing project wrong project which does not exist", updatedApp.Status.Conditions[0].Message) - assert.Equal(t, argoappv1.ApplicationConditionInvalidSpecError, updatedApp.Status.Conditions[0].Type) + assert.Equal(t, v1alpha1.ApplicationConditionInvalidSpecError, updatedApp.Status.Conditions[0].Type) } func TestFinalizeProjectDeletion_HasApplications(t *testing.T) { app := newFakeApp() - proj := &argoappv1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace}} - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, proj}}) + proj := &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace}} + 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) @@ -1114,8 +1541,8 @@ func TestFinalizeProjectDeletion_HasApplications(t *testing.T) { } func TestFinalizeProjectDeletion_DoesNotHaveApplications(t *testing.T) { - proj := &argoappv1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace}} - ctrl := newFakeController(&fakeData{apps: []runtime.Object{&defaultProj}}) + proj := &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace}} + ctrl := newFakeController(&fakeData{apps: []runtime.Object{&defaultProj}}, nil) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) receivedPatch := map[string]interface{}{} @@ -1123,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) @@ -1138,17 +1565,17 @@ func TestFinalizeProjectDeletion_DoesNotHaveApplications(t *testing.T) { func TestProcessRequestedAppOperation_FailedNoRetries(t *testing.T) { app := newFakeApp() app.Spec.Project = "default" - app.Operation = &argoappv1.Operation{ - Sync: &argoappv1.SyncOperation{}, + 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) @@ -1160,13 +1587,13 @@ func TestProcessRequestedAppOperation_FailedNoRetries(t *testing.T) { func TestProcessRequestedAppOperation_InvalidDestination(t *testing.T) { app := newFakeAppWithDestMismatch() app.Spec.Project = "test-project" - app.Operation = &argoappv1.Operation{ - Sync: &argoappv1.SyncOperation{}, + app.Operation = &v1alpha1.Operation{ + Sync: &v1alpha1.SyncOperation{}, } 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() { @@ -1176,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 }) }() @@ -1191,18 +1618,18 @@ func TestProcessRequestedAppOperation_InvalidDestination(t *testing.T) { func TestProcessRequestedAppOperation_FailedHasRetries(t *testing.T) { app := newFakeApp() app.Spec.Project = "invalid-project" - app.Operation = &argoappv1.Operation{ - Sync: &argoappv1.SyncOperation{}, - Retry: argoappv1.RetryStrategy{Limit: 1}, + app.Operation = &v1alpha1.Operation{ + 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) @@ -1217,12 +1644,12 @@ func TestProcessRequestedAppOperation_FailedHasRetries(t *testing.T) { func TestProcessRequestedAppOperation_RunningPreviouslyFailed(t *testing.T) { app := newFakeApp() - app.Operation = &argoappv1.Operation{ - Sync: &argoappv1.SyncOperation{}, - Retry: argoappv1.RetryStrategy{Limit: 1}, + app.Operation = &v1alpha1.Operation{ + Sync: &v1alpha1.SyncOperation{}, + Retry: v1alpha1.RetryStrategy{Limit: 1}, } app.Status.OperationState.Phase = synccommon.OperationRunning - app.Status.OperationState.SyncResult.Resources = []*argoappv1.ResourceResult{{ + app.Status.OperationState.SyncResult.Resources = []*v1alpha1.ResourceResult{{ Name: "guestbook", Kind: "Deployment", Group: "apps", @@ -1238,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) @@ -1256,9 +1683,9 @@ func TestProcessRequestedAppOperation_RunningPreviouslyFailed(t *testing.T) { func TestProcessRequestedAppOperation_HasRetriesTerminated(t *testing.T) { app := newFakeApp() - app.Operation = &argoappv1.Operation{ - Sync: &argoappv1.SyncOperation{}, - Retry: argoappv1.RetryStrategy{Limit: 10}, + app.Operation = &v1alpha1.Operation{ + Sync: &v1alpha1.SyncOperation{}, + Retry: v1alpha1.RetryStrategy{Limit: 10}, } app.Status.OperationState.Phase = synccommon.OperationTerminating @@ -1271,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) @@ -1298,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 @@ -1328,19 +1755,19 @@ func TestGetAppHosts(t *testing.T) { })).Return(nil) ctrl.stateCache = mockStateCache - hosts, err := ctrl.getAppHosts(app, []argoappv1.ResourceNode{{ - ResourceRef: argoappv1.ResourceRef{Name: "pod1", Namespace: "default", Kind: kube.PodKind}, - Info: []argoappv1.InfoItem{{ + hosts, err := ctrl.getAppHosts(app, []v1alpha1.ResourceNode{{ + ResourceRef: v1alpha1.ResourceRef{Name: "pod1", Namespace: "default", Kind: kube.PodKind}, + Info: []v1alpha1.InfoItem{{ Name: "Host", Value: "Minikube", }}, }}) assert.NoError(t, err) - assert.Equal(t, []argoappv1.HostInfo{{ + assert.Equal(t, []v1alpha1.HostInfo{{ Name: "minikube", SystemInfo: corev1.NodeSystemInfo{OSImage: "debian"}, - ResourcesInfo: []argoappv1.HostResourceInfo{{ + ResourcesInfo: []v1alpha1.HostResourceInfo{{ ResourceName: corev1.ResourceCPU, Capacity: 5000, RequestedByApp: 1000, RequestedByNeighbors: 2000}, }}}, hosts) } @@ -1348,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 @@ -1373,3 +1800,113 @@ func TestToAppKey(t *testing.T) { }) } } + +func Test_canProcessApp(t *testing.T) { + app := newFakeApp() + 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" + canProcess := ctrl.canProcessApp(app) + assert.True(t, canProcess) + }) + t.Run("without cluster filter, bad namespace", func(t *testing.T) { + app.Namespace = "bad" + canProcess := ctrl.canProcessApp(app) + assert.False(t, canProcess) + }) + t.Run("with cluster filter, good namespace", func(t *testing.T) { + app.Namespace = "good" + canProcess := ctrl.canProcessApp(app) + assert.True(t, canProcess) + }) + t.Run("with cluster filter, bad namespace", func(t *testing.T) { + app.Namespace = "bad" + canProcess := ctrl.canProcessApp(app) + assert.False(t, canProcess) + }) +} + +func Test_canProcessAppSkipReconcileAnnotation(t *testing.T) { + appSkipReconcileInvalid := newFakeApp() + appSkipReconcileInvalid.Annotations = map[string]string{common.AnnotationKeyAppSkipReconcile: "invalid-value"} + appSkipReconcileFalse := newFakeApp() + appSkipReconcileFalse.Annotations = map[string]string{common.AnnotationKeyAppSkipReconcile: "false"} + appSkipReconcileTrue := newFakeApp() + appSkipReconcileTrue.Annotations = map[string]string{common.AnnotationKeyAppSkipReconcile: "true"} + ctrl := newFakeController(&fakeData{}, nil) + tests := []struct { + name string + input interface{} + expected bool + }{ + {"No skip reconcile annotation", newFakeApp(), true}, + {"Contains skip reconcile annotation ", appSkipReconcileInvalid, true}, + {"Contains skip reconcile annotation value false", appSkipReconcileFalse, true}, + {"Contains skip reconcile annotation value true", appSkipReconcileTrue, false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, ctrl.canProcessApp(tt.input)) + }) + } +} + +func Test_syncDeleteOption(t *testing.T) { + app := newFakeApp() + 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) + delete := ctrl.shouldBeDeleted(app, cmObj) + assert.True(t, delete) + }) + t.Run("with delete set to false object is retained", func(t *testing.T) { + cmObj := kube.MustToUnstructured(&cm) + cmObj.SetAnnotations(map[string]string{"argocd.argoproj.io/sync-options": "Delete=false"}) + delete := ctrl.shouldBeDeleted(app, cmObj) + assert.False(t, delete) + }) + t.Run("with delete set to false object is retained", func(t *testing.T) { + cmObj := kube.MustToUnstructured(&cm) + cmObj.SetAnnotations(map[string]string{"helm.sh/resource-policy": "keep"}) + delete := ctrl.shouldBeDeleted(app, cmObj) + assert.False(t, delete) + }) +} + +func TestAddControllerNamespace(t *testing.T) { + t.Run("set controllerNamespace when the app is in the controller namespace", func(t *testing.T) { + app := newFakeApp() + ctrl := newFakeController(&fakeData{ + apps: []runtime.Object{app, &defaultProj}, + manifestResponse: &apiclient.ManifestResponse{}, + }, nil) + + ctrl.processAppRefreshQueueItem() + + updatedApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).Get(context.Background(), app.Name, metav1.GetOptions{}) + assert.NoError(t, err) + assert.Equal(t, test.FakeArgoCDNamespace, updatedApp.Status.ControllerNamespace) + }) + t.Run("set controllerNamespace when the app is in another namespace than the controller", func(t *testing.T) { + appNamespace := "app-namespace" + + app := newFakeApp() + app.ObjectMeta.Namespace = appNamespace + proj := defaultProj + proj.Spec.SourceNamespaces = []string{appNamespace} + ctrl := newFakeController(&fakeData{ + apps: []runtime.Object{app, &proj}, + manifestResponse: &apiclient.ManifestResponse{}, + applicationNamespaces: []string{appNamespace}, + }, nil) + + ctrl.processAppRefreshQueueItem() + + updatedApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(appNamespace).Get(context.Background(), app.Name, metav1.GetOptions{}) + assert.NoError(t, err) + assert.Equal(t, test.FakeArgoCDNamespace, updatedApp.Status.ControllerNamespace) + }) +} diff --git a/controller/cache/cache.go b/controller/cache/cache.go index 23cde35a5bd19..826079d62cda3 100644 --- a/controller/cache/cache.go +++ b/controller/cache/cache.go @@ -25,9 +25,12 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/rest" "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" "github.com/argoproj/argo-cd/v2/util/db" @@ -44,18 +47,21 @@ const ( // EnvClusterCacheWatchResyncDuration is the env variable that holds cluster cache watch re-sync duration EnvClusterCacheWatchResyncDuration = "ARGOCD_CLUSTER_CACHE_WATCH_RESYNC_DURATION" - // EnvClusterRetryTimeoutDuration is the env variable that holds cluster retry duration when sync error happens + // EnvClusterSyncRetryTimeoutDuration is the env variable that holds cluster retry duration when sync error happens EnvClusterSyncRetryTimeoutDuration = "ARGOCD_CLUSTER_SYNC_RETRY_TIMEOUT_DURATION" // EnvClusterCacheListPageSize is the env variable to control size of the list page size when making K8s queries EnvClusterCacheListPageSize = "ARGOCD_CLUSTER_CACHE_LIST_PAGE_SIZE" + // EnvClusterCacheListPageBufferSize is the env variable to control the number of pages to buffer when making a K8s query to list resources + EnvClusterCacheListPageBufferSize = "ARGOCD_CLUSTER_CACHE_LIST_PAGE_BUFFER_SIZE" + // EnvClusterCacheListSemaphore is the env variable to control size of the list semaphore // This is used to limit the number of concurrent memory consuming operations on the // k8s list queries results across all clusters to avoid memory spikes during cache initialization. EnvClusterCacheListSemaphore = "ARGOCD_CLUSTER_CACHE_LIST_SEMAPHORE" - // EnvClusterCacheRetryLimit is the env variable to control the retry limit for listing resources during cluster cache sync + // EnvClusterCacheAttemptLimit is the env variable to control the retry limit for listing resources during cluster cache sync EnvClusterCacheAttemptLimit = "ARGOCD_CLUSTER_CACHE_ATTEMPT_LIMIT" // EnvClusterCacheRetryUseBackoff is the env variable to control whether to use a backoff strategy with the retry during cluster cache sync @@ -82,6 +88,9 @@ var ( // 500 is equal to kubectl's size clusterCacheListPageSize int64 = 500 + // clusterCacheListPageBufferSize is the number of pages to buffer when performing K8s list requests + clusterCacheListPageBufferSize int32 = 1 + // clusterCacheRetryLimit sets a retry limit for failed requests during cluster cache sync // If set to 1, retries are disabled. clusterCacheAttemptLimit int32 = 1 @@ -95,8 +104,9 @@ func init() { clusterCacheWatchResyncDuration = env.ParseDurationFromEnv(EnvClusterCacheWatchResyncDuration, clusterCacheWatchResyncDuration, 0, math.MaxInt64) clusterSyncRetryTimeoutDuration = env.ParseDurationFromEnv(EnvClusterSyncRetryTimeoutDuration, clusterSyncRetryTimeoutDuration, 0, math.MaxInt64) clusterCacheListPageSize = env.ParseInt64FromEnv(EnvClusterCacheListPageSize, clusterCacheListPageSize, 0, math.MaxInt64) + clusterCacheListPageBufferSize = int32(env.ParseNumFromEnv(EnvClusterCacheListPageBufferSize, int(clusterCacheListPageBufferSize), 1, math.MaxInt32)) clusterCacheListSemaphoreSize = env.ParseInt64FromEnv(EnvClusterCacheListSemaphore, clusterCacheListSemaphoreSize, 0, math.MaxInt64) - clusterCacheAttemptLimit = int32(env.ParseInt64FromEnv(EnvClusterCacheAttemptLimit, 1, 1, math.MaxInt32)) + clusterCacheAttemptLimit = int32(env.ParseNumFromEnv(EnvClusterCacheAttemptLimit, int(clusterCacheAttemptLimit), 1, math.MaxInt32)) clusterCacheRetryUseBackoff = env.ParseBoolFromEnv(EnvClusterCacheRetryUseBackoff, false) } @@ -148,6 +158,8 @@ type ResourceInfo struct { PodInfo *PodInfo // NodeInfo is available for nodes only NodeInfo *NodeInfo + + manifestHash string } func NewLiveStateCache( @@ -157,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{ @@ -168,7 +180,7 @@ func NewLiveStateCache( kubectl: kubectl, settingsMgr: settingsMgr, metricsServer: metricsServer, - clusterFilter: clusterFilter, + clusterSharding: clusterSharding, resourceTracking: resourceTracking, } } @@ -177,6 +189,11 @@ type cacheSettings struct { clusterSettings clustercache.Settings appInstanceLabelKey string trackingMethod appv1.TrackingMethod + // resourceOverrides provides a list of ignored differences to ignore watched resource updates + resourceOverrides map[string]appv1.ResourceOverride + + // ignoreResourceUpdates is a flag to enable resource-ignore rules. + ignoreResourceUpdatesEnabled bool } type liveStateCache struct { @@ -186,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 @@ -199,6 +216,14 @@ func (c *liveStateCache) loadCacheSettings() (*cacheSettings, error) { if err != nil { return nil, err } + resourceUpdatesOverrides, err := c.settingsMgr.GetIgnoreResourceUpdatesOverrides() + if err != nil { + return nil, err + } + ignoreResourceUpdatesEnabled, err := c.settingsMgr.GetIsIgnoreResourceUpdatesEnabled() + if err != nil { + return nil, err + } resourcesFilter, err := c.settingsMgr.GetResourcesFilter() if err != nil { return nil, err @@ -211,7 +236,8 @@ func (c *liveStateCache) loadCacheSettings() (*cacheSettings, error) { ResourceHealthOverride: lua.ResourceHealthOverrides(resourceOverrides), ResourcesFilter: resourcesFilter, } - return &cacheSettings{clusterSettings, appInstanceLabelKey, argo.GetTrackingMethod(c.settingsMgr)}, nil + + return &cacheSettings{clusterSettings, appInstanceLabelKey, argo.GetTrackingMethod(c.settingsMgr), resourceUpdatesOverrides, ignoreResourceUpdatesEnabled}, nil } func asResourceNode(r *clustercache.Resource) appv1.ResourceNode { @@ -308,6 +334,27 @@ func skipAppRequeuing(key kube.ResourceKey) bool { return ignoredRefreshResources[key.Group+"/"+key.Kind] } +func skipResourceUpdate(oldInfo, newInfo *ResourceInfo) bool { + if oldInfo == nil || newInfo == nil { + return false + } + isSameHealthStatus := (oldInfo.Health == nil && newInfo.Health == nil) || oldInfo.Health != nil && newInfo.Health != nil && oldInfo.Health.Status == newInfo.Health.Status + isSameManifest := oldInfo.manifestHash != "" && newInfo.manifestHash != "" && oldInfo.manifestHash == newInfo.manifestHash + return isSameHealthStatus && isSameManifest +} + +// shouldHashManifest validates if the API resource needs to be hashed. +// If there's an app name from resource tracking, or if this is itself an app, we should generate a hash. +// Otherwise, the hashing should be skipped to save CPU time. +func shouldHashManifest(appName string, gvk schema.GroupVersionKind) bool { + // Only hash if the resource belongs to an app. + // Best - Only hash for resources that are part of an app or their dependencies + // (current) - Only hash for resources that are part of an app + all apps that might be from an ApplicationSet + // Orphan - If orphan is enabled, hash should be made on all resource of that namespace and a config to disable it + // Worst - Hash all resources watched by Argo + return appName != "" || (gvk.Group == application.Group && gvk.Kind == application.ApplicationKind) +} + // isRetryableError is a helper method to see whether an error // returned from the dynamic client is potentially retryable. func isRetryableError(err error) bool { @@ -325,9 +372,14 @@ func isRetryableError(err error) bool { isResourceQuotaConflictErr(err) || isTransientNetworkErr(err) || isExceededQuotaErr(err) || + isHTTP2GoawayErr(err) || errors.Is(err, syscall.ECONNRESET) } +func isHTTP2GoawayErr(err error) bool { + return strings.Contains(err.Error(), "http2: server sent GOAWAY and closed the connection") +} + func isExceededQuotaErr(err error) bool { return kerrors.IsForbidden(err) && strings.Contains(err.Error(), "exceeded quota") } @@ -385,6 +437,10 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e return nil, fmt.Errorf("error getting cluster: %w", err) } + if c.clusterSharding == nil { + return nil, fmt.Errorf("unable to handle cluster %s: cluster sharding is not configured", cluster.Server) + } + if !c.canHandleCluster(cluster) { return nil, fmt.Errorf("controller is configured to ignore cluster %s", cluster.Server) } @@ -394,9 +450,29 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e return nil, fmt.Errorf("error getting custom label: %w", err) } + respectRBAC, err := c.settingsMgr.RespectRBAC() + if err != nil { + return nil, fmt.Errorf("error getting value for %v: %w", settings.RespectRBAC, err) + } + + clusterCacheConfig := cluster.RESTConfig() + // Controller dynamically fetches all resource types available on the cluster + // using a discovery API that may contain deprecated APIs. + // This causes log flooding when managing a large number of clusters. + // https://github.com/argoproj/argo-cd/issues/11973 + // However, we can safely suppress deprecation warnings + // because we do not rely on resources with a particular API group or version. + // https://kubernetes.io/blog/2020/09/03/warnings/#customize-client-handling + // + // Completely suppress warning logs only for log levels that are less than Debug. + if log.GetLevel() < log.DebugLevel { + clusterCacheConfig.WarningHandler = rest.NoWarnings{} + } + clusterCacheOpts := []clustercache.UpdateSettingsFunc{ clustercache.SetListSemaphore(semaphore.NewWeighted(clusterCacheListSemaphoreSize)), clustercache.SetListPageSize(clusterCacheListPageSize), + clustercache.SetListPageBufferSize(clusterCacheListPageBufferSize), clustercache.SetWatchResyncTimeout(clusterCacheWatchResyncDuration), clustercache.SetClusterSyncRetryTimeout(clusterSyncRetryTimeoutDuration), clustercache.SetResyncTimeout(clusterCacheResyncDuration), @@ -409,23 +485,35 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e c.lock.RLock() cacheSettings := c.cacheSettings c.lock.RUnlock() + res.Health, _ = health.GetResourceHealth(un, cacheSettings.clusterSettings.ResourceHealthOverride) appName := c.resourceTracking.GetAppName(un, cacheSettings.appInstanceLabelKey, cacheSettings.trackingMethod) if isRoot && appName != "" { res.AppName = appName } + gvk := un.GroupVersionKind() + if cacheSettings.ignoreResourceUpdatesEnabled && shouldHashManifest(appName, gvk) { + hash, err := generateManifestHash(un, nil, cacheSettings.resourceOverrides) + if err != nil { + log.Errorf("Failed to generate manifest hash: %v", err) + } else { + res.manifestHash = hash + } + } + // edge case. we do not label CRDs, so they miss the tracking label we inject. But we still // want the full resource to be available in our cache (to diff), so we store all CRDs return res, res.AppName != "" || gvk.Kind == kube.CustomResourceDefinitionKind }), clustercache.SetLogr(logutils.NewLogrusLogger(log.WithField("server", cluster.Server))), clustercache.SetRetryOptions(clusterCacheAttemptLimit, clusterCacheRetryUseBackoff, isRetryableError), + clustercache.SetRespectRBAC(respectRBAC), } - clusterCache = clustercache.NewClusterCache(cluster.RESTConfig(), clusterCacheOpts...) + clusterCache = clustercache.NewClusterCache(clusterCacheConfig, clusterCacheOpts...) _ = clusterCache.OnResourceUpdated(func(newRes *clustercache.Resource, oldRes *clustercache.Resource, namespaceResources map[kube.ResourceKey]*clustercache.Resource) { toNotify := make(map[string]bool) @@ -435,6 +523,30 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e } else { ref = oldRes.Ref } + + c.lock.RLock() + cacheSettings := c.cacheSettings + c.lock.RUnlock() + + if cacheSettings.ignoreResourceUpdatesEnabled && oldRes != nil && newRes != nil && skipResourceUpdate(resInfo(oldRes), resInfo(newRes)) { + // Additional check for debug level so we don't need to evaluate the + // format string in case of non-debug scenarios + if log.GetLevel() >= log.DebugLevel { + namespace := ref.Namespace + if ref.Namespace == "" { + namespace = "(cluster-scoped)" + } + log.WithFields(log.Fields{ + "server": cluster.Server, + "namespace": namespace, + "name": ref.Name, + "api-version": ref.APIVersion, + "kind": ref.Kind, + }).Debug("Ignoring change of object because none of the watched resource fields have changed") + } + return + } + for _, r := range []*clustercache.Resource{newRes, oldRes} { if r == nil { continue @@ -473,10 +585,11 @@ func (c *liveStateCache) getSyncedCluster(server string) (clustercache.ClusterCa func (c *liveStateCache) invalidate(cacheSettings cacheSettings) { log.Info("invalidating live state cache") c.lock.Lock() - defer c.lock.Unlock() - c.cacheSettings = cacheSettings - for _, clust := range c.clusters { + clusters := c.clusters + c.lock.Unlock() + + for _, clust := range clusters { clust.Invalidate(clustercache.SetSettings(cacheSettings.clusterSettings)) } log.Info("live state cache invalidated") @@ -531,7 +644,7 @@ func (c *liveStateCache) GetNamespaceTopLevelResources(server string, namespace func (c *liveStateCache) GetManagedLiveObjs(a *appv1.Application, targetObjs []*unstructured.Unstructured) (map[kube.ResourceKey]*unstructured.Unstructured, error) { clusterInfo, err := c.getSyncedCluster(a.Spec.Destination.Server) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to get cluster info for %q: %w", a.Spec.Destination.Server, err) } return clusterInfo.GetManagedLiveObjs(targetObjs, func(r *clustercache.Resource) bool { return resInfo(r).AppName == a.InstanceName(c.settingsMgr.GetNamespace()) @@ -541,7 +654,7 @@ func (c *liveStateCache) GetManagedLiveObjs(a *appv1.Application, targetObjs []* func (c *liveStateCache) GetVersionsInfo(serverURL string) (string, []kube.APIResourceInfo, error) { clusterInfo, err := c.getSyncedCluster(serverURL) if err != nil { - return "", nil, err + return "", nil, fmt.Errorf("failed to get cluster info for %q: %w", serverURL, err) } return clusterInfo.GetServerVersion(), clusterInfo.GetAPIResources(), nil } @@ -619,22 +732,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 @@ -645,6 +760,7 @@ func (c *liveStateCache) handleAddEvent(cluster *appv1.Cluster) { } func (c *liveStateCache) handleModEvent(oldCluster *appv1.Cluster, newCluster *appv1.Cluster) { + c.clusterSharding.Update(oldCluster, newCluster) c.lock.Lock() cluster, ok := c.clusters[newCluster.Server] c.lock.Unlock() @@ -686,12 +802,15 @@ func (c *liveStateCache) handleModEvent(oldCluster *appv1.Cluster, newCluster *a } func (c *liveStateCache) handleDeleteEvent(clusterServer string) { - c.lock.Lock() - defer c.lock.Unlock() + c.lock.RLock() + c.clusterSharding.Delete(clusterServer) cluster, ok := c.clusters[clusterServer] + c.lock.RUnlock() if ok { cluster.Invalidate() + c.lock.Lock() delete(c.clusters, clusterServer) + c.lock.Unlock() } } diff --git a/controller/cache/cache_test.go b/controller/cache/cache_test.go index 9d1fad82b0279..53a03ca81995e 100644 --- a/controller/cache/cache_test.go +++ b/controller/cache/cache_test.go @@ -1,22 +1,32 @@ package cache import ( + "context" "errors" "net" "net/url" + "sync" "testing" + "time" "github.com/stretchr/testify/assert" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" apierr "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "github.com/argoproj/gitops-engine/pkg/cache" "github.com/argoproj/gitops-engine/pkg/cache/mocks" + "github.com/argoproj/gitops-engine/pkg/health" "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" ) type netError string @@ -29,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{ @@ -50,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{ @@ -69,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{ @@ -93,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", @@ -107,6 +129,100 @@ func TestHandleAddEvent_ClusterExcluded(t *testing.T) { assert.Len(t, clustersCache.clusters, 0) } +func TestHandleDeleteEvent_CacheDeadlock(t *testing.T) { + testCluster := &appv1.Cluster{ + 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") + liveStateCacheLock := sync.RWMutex{} + gitopsEngineClusterCache := &mocks.ClusterCache{} + clustersCache := liveStateCache{ + clusters: map[string]cache.ClusterCache{ + testCluster.Server: gitopsEngineClusterCache, + }, + 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: liveStateCacheLock, + } + channel := make(chan string) + // Mocked lock held by the gitops-engine cluster cache + 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 + // handleDeleteEvent -> Locks liveStateCache + // EnsureSynced via sync, newResource, populateResourceInfoHandler -> attempts to Lock liveStateCache + // handleDeleteEvent via cluster.Invalidate -> attempts to Lock gitops-engine + handleDeleteWasCalled := sync.Mutex{} + engineHoldsEngineLock := sync.Mutex{} + ensureSyncedCompleted.Lock() + invalidateCompleted.Lock() + handleDeleteWasCalled.Lock() + engineHoldsEngineLock.Lock() + + gitopsEngineClusterCache.On("EnsureSynced").Run(func(args mock.Arguments) { + gitopsEngineClusterCacheLock.Lock() + t.Log("EnsureSynced: Engine has engine lock") + engineHoldsEngineLock.Unlock() + defer gitopsEngineClusterCacheLock.Unlock() + // Wait until handleDeleteEvent holds the liveStateCache lock + handleDeleteWasCalled.Lock() + // 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) { + // 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 + go func() { + err := gitopsEngineClusterCache.EnsureSynced() + if err != nil { + assert.Fail(t, err.Error()) + } + }() + // Run in background + go clustersCache.handleDeleteEvent(testCluster.Server) + // Allow execution to continue on clusters cache call to trigger lock + ensureSyncedCompleted.Lock() + invalidateCompleted.Lock() + t.Log("Competing functions were able to obtain locks") + invalidateCompleted.Unlock() + ensureSyncedCompleted.Unlock() + channel <- "PASSED" + }() + select { + case str := <-channel: + assert.Equal(t, "PASSED", str, str) + case <-time.After(5 * time.Second): + assert.Fail(t, "Ended up in deadlock") + } +} + func TestIsRetryableError(t *testing.T) { var ( tlsHandshakeTimeoutErr net.Error = netError("net/http: TLS handshake timeout") @@ -202,3 +318,126 @@ func Test_asResourceNode_owner_refs(t *testing.T) { } assert.Equal(t, expected, resNode) } + +func TestSkipResourceUpdate(t *testing.T) { + var ( + hash1_x string = "x" + hash2_y string = "y" + hash3_x string = "x" + ) + info := &ResourceInfo{ + manifestHash: hash1_x, + Health: &health.HealthStatus{ + Status: health.HealthStatusHealthy, + Message: "default", + }, + } + t.Run("Nil", func(t *testing.T) { + assert.False(t, skipResourceUpdate(nil, nil)) + }) + t.Run("From Nil", func(t *testing.T) { + assert.False(t, skipResourceUpdate(nil, info)) + }) + t.Run("To Nil", func(t *testing.T) { + assert.False(t, skipResourceUpdate(info, nil)) + }) + t.Run("No hash", func(t *testing.T) { + assert.False(t, skipResourceUpdate(&ResourceInfo{}, &ResourceInfo{})) + }) + t.Run("Same hash", func(t *testing.T) { + assert.True(t, skipResourceUpdate(&ResourceInfo{ + manifestHash: hash1_x, + }, &ResourceInfo{ + manifestHash: hash1_x, + })) + }) + t.Run("Same hash value", func(t *testing.T) { + assert.True(t, skipResourceUpdate(&ResourceInfo{ + manifestHash: hash1_x, + }, &ResourceInfo{ + manifestHash: hash3_x, + })) + }) + t.Run("Different hash value", func(t *testing.T) { + assert.False(t, skipResourceUpdate(&ResourceInfo{ + manifestHash: hash1_x, + }, &ResourceInfo{ + manifestHash: hash2_y, + })) + }) + t.Run("Same hash, empty health", func(t *testing.T) { + assert.True(t, skipResourceUpdate(&ResourceInfo{ + manifestHash: hash1_x, + Health: &health.HealthStatus{}, + }, &ResourceInfo{ + manifestHash: hash3_x, + Health: &health.HealthStatus{}, + })) + }) + t.Run("Same hash, old health", func(t *testing.T) { + assert.False(t, skipResourceUpdate(&ResourceInfo{ + manifestHash: hash1_x, + Health: &health.HealthStatus{ + Status: health.HealthStatusHealthy}, + }, &ResourceInfo{ + manifestHash: hash3_x, + Health: nil, + })) + }) + t.Run("Same hash, new health", func(t *testing.T) { + assert.False(t, skipResourceUpdate(&ResourceInfo{ + manifestHash: hash1_x, + Health: &health.HealthStatus{}, + }, &ResourceInfo{ + manifestHash: hash3_x, + Health: &health.HealthStatus{ + Status: health.HealthStatusHealthy, + }, + })) + }) + t.Run("Same hash, same health", func(t *testing.T) { + assert.True(t, skipResourceUpdate(&ResourceInfo{ + manifestHash: hash1_x, + Health: &health.HealthStatus{ + Status: health.HealthStatusHealthy, + Message: "same", + }, + }, &ResourceInfo{ + manifestHash: hash3_x, + Health: &health.HealthStatus{ + Status: health.HealthStatusHealthy, + Message: "same", + }, + })) + }) + t.Run("Same hash, different health status", func(t *testing.T) { + assert.False(t, skipResourceUpdate(&ResourceInfo{ + manifestHash: hash1_x, + Health: &health.HealthStatus{ + Status: health.HealthStatusHealthy, + Message: "same", + }, + }, &ResourceInfo{ + manifestHash: hash3_x, + Health: &health.HealthStatus{ + Status: health.HealthStatusDegraded, + Message: "same", + }, + })) + }) + t.Run("Same hash, different health message", func(t *testing.T) { + assert.True(t, skipResourceUpdate(&ResourceInfo{ + manifestHash: hash1_x, + Health: &health.HealthStatus{ + Status: health.HealthStatusHealthy, + Message: "same", + }, + }, &ResourceInfo{ + manifestHash: hash3_x, + Health: &health.HealthStatus{ + Status: health.HealthStatusHealthy, + Message: "different", + }, + })) + }) +} diff --git a/controller/cache/info.go b/controller/cache/info.go index 3cc7980ad8e12..53512de6b713a 100644 --- a/controller/cache/info.go +++ b/controller/cache/info.go @@ -3,12 +3,14 @@ package cache import ( "errors" "fmt" + "strconv" "strings" "k8s.io/apimachinery/pkg/runtime/schema" "github.com/argoproj/gitops-engine/pkg/utils/kube" "github.com/argoproj/gitops-engine/pkg/utils/text" + "github.com/cespare/xxhash/v2" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -16,6 +18,7 @@ import ( "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/v2/util/argo/normalizers" "github.com/argoproj/argo-cd/v2/util/resource" ) @@ -34,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 { @@ -55,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 { @@ -90,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) { @@ -260,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) { @@ -371,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) { @@ -386,3 +407,27 @@ func populateHostNodeInfo(un *unstructured.Unstructured, res *ResourceInfo) { SystemInfo: node.Status.NodeInfo, } } + +func generateManifestHash(un *unstructured.Unstructured, ignores []v1alpha1.ResourceIgnoreDifferences, overrides map[string]v1alpha1.ResourceOverride) (string, error) { + normalizer, err := normalizers.NewIgnoreNormalizer(ignores, overrides) + if err != nil { + return "", fmt.Errorf("error creating normalizer: %w", err) + } + + resource := un.DeepCopy() + err = normalizer.Normalize(resource) + if err != nil { + return "", fmt.Errorf("error normalizing resource: %w", err) + } + + data, err := resource.MarshalJSON() + if err != nil { + return "", fmt.Errorf("error marshaling resource: %w", err) + } + hash := hash(data) + return hash, nil +} + +func hash(data []byte) string { + return strconv.FormatUint(xxhash.Sum64(data), 16) +} diff --git a/controller/cache/info_test.go b/controller/cache/info_test.go index 6c9977876bae0..7b48040009284 100644 --- a/controller/cache/info_test.go +++ b/controller/cache/info_test.go @@ -9,11 +9,11 @@ import ( "github.com/argoproj/gitops-engine/pkg/utils/kube" "github.com/argoproj/pkg/errors" - "github.com/ghodss/yaml" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" ) @@ -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) @@ -694,3 +694,62 @@ func TestCustomLabel(t *testing.T) { assert.Equal(t, "other-label", info.Info[1].Name) assert.Equal(t, "value2", info.Info[1].Value) } + +func TestManifestHash(t *testing.T) { + manifest := strToUnstructured(` + apiVersion: v1 + kind: Pod + metadata: + name: helm-guestbook-pod + namespace: default + ownerReferences: + - apiVersion: extensions/v1beta1 + kind: ReplicaSet + name: helm-guestbook-rs + resourceVersion: "123" + labels: + app: guestbook + spec: + nodeName: minikube + containers: + - image: bar + resources: + requests: + memory: 128Mi +`) + + ignores := []v1alpha1.ResourceIgnoreDifferences{ + { + Group: "*", + Kind: "*", + JSONPointers: []string{"/metadata/resourceVersion"}, + }, + } + + data, _ := strToUnstructured(` + apiVersion: v1 + kind: Pod + metadata: + name: helm-guestbook-pod + namespace: default + ownerReferences: + - apiVersion: extensions/v1beta1 + kind: ReplicaSet + name: helm-guestbook-rs + labels: + app: guestbook + spec: + nodeName: minikube + containers: + - image: bar + resources: + requests: + memory: 128Mi +`).MarshalJSON() + + expected := hash(data) + + hash, err := generateManifestHash(manifest, ignores, nil) + assert.Equal(t, expected, hash) + assert.Nil(t, err) +} diff --git a/controller/clusterinfoupdater.go b/controller/clusterinfoupdater.go index 04ec12dec5040..d87cdad6be85d 100644 --- a/controller/clusterinfoupdater.go +++ b/controller/clusterinfoupdater.go @@ -2,8 +2,11 @@ package controller import ( "context" - "time" "fmt" + "github.com/argoproj/argo-cd/v2/common" + "time" + + "github.com/argoproj/argo-cd/v2/util/env" "github.com/argoproj/gitops-engine/pkg/cache" "github.com/argoproj/gitops-engine/pkg/utils/kube" log "github.com/sirupsen/logrus" @@ -19,7 +22,13 @@ import ( ) const ( - secretUpdateInterval = 10 * time.Second + defaultSecretUpdateInterval = 10 * time.Second + + EnvClusterInfoTimeout = "ARGO_CD_UPDATE_CLUSTER_INFO_TIMEOUT" +) + +var ( + clusterInfoTimeout = env.ParseDurationFromEnv(EnvClusterInfoTimeout, defaultSecretUpdateInterval, defaultSecretUpdateInterval, 1*time.Minute) ) type clusterInfoUpdater struct { @@ -30,6 +39,7 @@ type clusterInfoUpdater struct { clusterFilter func(cluster *appv1.Cluster) bool projGetter func(app *appv1.Application) (*appv1.AppProject, error) namespace string + lastUpdated time.Time } func NewClusterInfoUpdater( @@ -41,17 +51,17 @@ func NewClusterInfoUpdater( projGetter func(app *appv1.Application) (*appv1.AppProject, error), namespace string) *clusterInfoUpdater { - return &clusterInfoUpdater{infoSource, db, appLister, cache, clusterFilter, projGetter, namespace} + return &clusterInfoUpdater{infoSource, db, appLister, cache, clusterFilter, projGetter, namespace, time.Time{}} } func (c *clusterInfoUpdater) Run(ctx context.Context) { c.updateClusters() - ticker := time.NewTicker(secretUpdateInterval) + ticker := time.NewTicker(clusterInfoTimeout) for { select { case <-ctx.Done(): ticker.Stop() - break + return case <-ticker.C: c.updateClusters() } @@ -59,13 +69,23 @@ func (c *clusterInfoUpdater) Run(ctx context.Context) { } func (c *clusterInfoUpdater) updateClusters() { + if time.Since(c.lastUpdated) < clusterInfoTimeout { + return + } + + ctx, cancel := context.WithTimeout(context.Background(), clusterInfoTimeout) + defer func() { + cancel() + c.lastUpdated = time.Now() + }() + infoByServer := make(map[string]*cache.ClusterInfo) clustersInfo := c.infoSource.GetClustersInfo() for i := range clustersInfo { info := clustersInfo[i] infoByServer[info.Server] = &info } - clusters, err := c.db.ListClusters(context.Background()) + clusters, err := c.db.ListClusters(ctx) if err != nil { log.Warnf("Failed to save clusters info: %v", err) return @@ -82,19 +102,28 @@ func (c *clusterInfoUpdater) updateClusters() { } _ = kube.RunAllAsync(len(clustersFiltered), func(i int) error { cluster := clustersFiltered[i] - if err := c.updateClusterInfo(cluster, infoByServer[cluster.Server]); err != nil { - log.Warnf("Failed to save clusters info: %v", err) + clusterInfo := infoByServer[cluster.Server] + if err := c.updateClusterInfo(ctx, cluster, clusterInfo); err != nil { + log.Warnf("Failed to save cluster info: %v", err) + } else if err := updateClusterLabels(ctx, clusterInfo, cluster, c.db.UpdateCluster); err != nil { + log.Warnf("Failed to update cluster labels: %v", err) } return nil }) log.Debugf("Successfully saved info of %d clusters", len(clustersFiltered)) } -func (c *clusterInfoUpdater) updateClusterInfo(cluster appv1.Cluster, info *cache.ClusterInfo) error { +func (c *clusterInfoUpdater) updateClusterInfo(ctx context.Context, cluster appv1.Cluster, info *cache.ClusterInfo) error { apps, err := c.appLister.List(labels.Everything()) if err != nil { return fmt.Errorf("error while fetching the apps list: %w", err) } + + updated := c.getUpdatedClusterInfo(ctx, apps, cluster, info, metav1.Now()) + return c.cache.SetClusterInfo(cluster.Server, &updated) +} + +func (c *clusterInfoUpdater) getUpdatedClusterInfo(ctx context.Context, apps []*appv1.Application, cluster appv1.Cluster, info *cache.ClusterInfo, now metav1.Time) appv1.ClusterInfo { var appCount int64 for _, a := range apps { if c.projGetter != nil { @@ -103,14 +132,13 @@ func (c *clusterInfoUpdater) updateClusterInfo(cluster appv1.Cluster, info *cach continue } } - if err := argo.ValidateDestination(context.Background(), &a.Spec.Destination, c.db); err != nil { + if err := argo.ValidateDestination(ctx, &a.Spec.Destination, c.db); err != nil { continue } if a.Spec.Destination.Server == cluster.Server { appCount += 1 } } - now := metav1.Now() clusterInfo := appv1.ClusterInfo{ ConnectionState: appv1.ConnectionState{ModifiedAt: &now}, ApplicationsCount: appCount, @@ -137,5 +165,15 @@ func (c *clusterInfoUpdater) updateClusterInfo(cluster appv1.Cluster, info *cach } } - return c.cache.SetClusterInfo(cluster.Server, &clusterInfo) + return clusterInfo +} + +func updateClusterLabels(ctx context.Context, clusterInfo *cache.ClusterInfo, cluster appv1.Cluster, updateCluster func(context.Context, *appv1.Cluster) (*appv1.Cluster, error)) error { + if clusterInfo != nil && cluster.Labels[common.LabelKeyAutoLabelClusterInfo] == "true" && cluster.Labels[common.LabelKeyClusterKubernetesVersion] != clusterInfo.K8SVersion { + cluster.Labels[common.LabelKeyClusterKubernetesVersion] = clusterInfo.K8SVersion + _, err := updateCluster(ctx, &cluster) + return err + } + + return nil } diff --git a/controller/clusterinfoupdater_test.go b/controller/clusterinfoupdater_test.go index 60f074d2cfd37..d11d4412bf30c 100644 --- a/controller/clusterinfoupdater_test.go +++ b/controller/clusterinfoupdater_test.go @@ -2,6 +2,7 @@ package controller import ( "context" + "errors" "fmt" "testing" "time" @@ -88,7 +89,7 @@ func TestClusterSecretUpdater(t *testing.T) { lister := applisters.NewApplicationLister(appInformer.GetIndexer()).Applications(fakeNamespace) updater := NewClusterInfoUpdater(nil, argoDB, lister, appCache, nil, nil, fakeNamespace) - err = updater.updateClusterInfo(*cluster, info) + err = updater.updateClusterInfo(context.Background(), *cluster, info) assert.NoError(t, err, "Invoking updateClusterInfo failed.") var clusterInfo v1alpha1.ClusterInfo @@ -98,3 +99,92 @@ func TestClusterSecretUpdater(t *testing.T) { assert.Equal(t, test.ExpectedStatus, clusterInfo.ConnectionState.Status) } } + +func TestUpdateClusterLabels(t *testing.T) { + shouldNotBeInvoked := func(ctx context.Context, cluster *v1alpha1.Cluster) (*v1alpha1.Cluster, error) { + shouldNotHappen := errors.New("if an error happens here, something's wrong") + assert.NoError(t, shouldNotHappen) + return nil, shouldNotHappen + } + tests := []struct { + name string + clusterInfo *clustercache.ClusterInfo + cluster v1alpha1.Cluster + updateCluster func(context.Context, *v1alpha1.Cluster) (*v1alpha1.Cluster, error) + wantErr assert.ErrorAssertionFunc + }{ + { + "enableClusterInfoLabels = false", + &clustercache.ClusterInfo{ + Server: "kubernetes.svc.local", + K8SVersion: "1.28", + }, + v1alpha1.Cluster{ + Server: "kubernetes.svc.local", + Labels: nil, + }, + shouldNotBeInvoked, + assert.NoError, + }, + { + "clusterInfo = nil", + nil, + v1alpha1.Cluster{ + Server: "kubernetes.svc.local", + Labels: map[string]string{"argocd.argoproj.io/auto-label-cluster-info": "true"}, + }, + shouldNotBeInvoked, + assert.NoError, + }, + { + "clusterInfo.k8sversion == cluster k8s label", + &clustercache.ClusterInfo{ + Server: "kubernetes.svc.local", + K8SVersion: "1.28", + }, + v1alpha1.Cluster{ + Server: "kubernetes.svc.local", + Labels: map[string]string{"argocd.argoproj.io/kubernetes-version": "1.28", "argocd.argoproj.io/auto-label-cluster-info": "true"}, + }, + shouldNotBeInvoked, + assert.NoError, + }, + { + "clusterInfo.k8sversion != cluster k8s label, no error", + &clustercache.ClusterInfo{ + Server: "kubernetes.svc.local", + K8SVersion: "1.28", + }, + v1alpha1.Cluster{ + Server: "kubernetes.svc.local", + Labels: map[string]string{"argocd.argoproj.io/kubernetes-version": "1.27", "argocd.argoproj.io/auto-label-cluster-info": "true"}, + }, + func(ctx context.Context, cluster *v1alpha1.Cluster) (*v1alpha1.Cluster, error) { + assert.Equal(t, cluster.Labels["argocd.argoproj.io/kubernetes-version"], "1.28") + return nil, nil + }, + assert.NoError, + }, + { + "clusterInfo.k8sversion != cluster k8s label, some error", + &clustercache.ClusterInfo{ + Server: "kubernetes.svc.local", + K8SVersion: "1.28", + }, + v1alpha1.Cluster{ + Server: "kubernetes.svc.local", + Labels: map[string]string{"argocd.argoproj.io/kubernetes-version": "1.27", "argocd.argoproj.io/auto-label-cluster-info": "true"}, + }, + func(ctx context.Context, cluster *v1alpha1.Cluster) (*v1alpha1.Cluster, error) { + assert.Equal(t, cluster.Labels["argocd.argoproj.io/kubernetes-version"], "1.28") + return nil, errors.New("some error happened while saving") + }, + assert.Error, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.wantErr(t, updateClusterLabels(context.Background(), tt.clusterInfo, tt.cluster, tt.updateCluster), fmt.Sprintf("updateClusterLabels(%v, %v, %v)", context.Background(), tt.clusterInfo, tt.cluster)) + }) + } +} diff --git a/controller/health.go b/controller/health.go index 34a1ea07a0132..b1acac8ac5b9b 100644 --- a/controller/health.go +++ b/controller/health.go @@ -1,10 +1,13 @@ package controller import ( + "fmt" + "github.com/argoproj/gitops-engine/pkg/health" hookutil "github.com/argoproj/gitops-engine/pkg/sync/hook" "github.com/argoproj/gitops-engine/pkg/sync/ignore" kubeutil "github.com/argoproj/gitops-engine/pkg/utils/kube" + log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/runtime/schema" "github.com/argoproj/argo-cd/v2/pkg/apis/application" @@ -15,6 +18,7 @@ import ( // setApplicationHealth updates the health statuses of all resources performed in the comparison func setApplicationHealth(resources []managedResource, statuses []appv1.ResourceStatus, resourceOverrides map[string]appv1.ResourceOverride, app *appv1.Application, persistResourceHealth bool) (*appv1.HealthStatus, error) { var savedErr error + var errCount uint appHealth := appv1.HealthStatus{Status: health.HealthStatusHealthy} for i, res := range resources { if res.Target != nil && hookutil.Skip(res.Target) { @@ -38,7 +42,10 @@ func setApplicationHealth(resources []managedResource, statuses []appv1.Resource } healthStatus, err = health.GetResourceHealth(res.Live, healthOverrides) if err != nil && savedErr == nil { - savedErr = err + errCount++ + savedErr = fmt.Errorf("failed to get resource health for %q with name %q in namespace %q: %w", res.Live.GetKind(), res.Live.GetName(), res.Live.GetNamespace(), err) + // also log so we don't lose the message + log.WithField("application", app.QualifiedName()).Warn(savedErr) } } @@ -72,5 +79,8 @@ func setApplicationHealth(resources []managedResource, statuses []appv1.Resource } else { app.Status.ResourceHealthSource = appv1.ResourceHealthLocationAppTree } + if savedErr != nil && errCount > 1 { + savedErr = fmt.Errorf("see applicaton-controller logs for %d other errors; most recent error was: %w", errCount-1, savedErr) + } return &appHealth, savedErr } diff --git a/controller/health_test.go b/controller/health_test.go index ed5cfad25b02e..caa53b446f733 100644 --- a/controller/health_test.go +++ b/controller/health_test.go @@ -7,11 +7,11 @@ import ( "github.com/argoproj/gitops-engine/pkg/health" synccommon "github.com/argoproj/gitops-engine/pkg/sync/common" "github.com/argoproj/gitops-engine/pkg/utils/kube" - "github.com/ghodss/yaml" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/pkg/apis/application" appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" @@ -124,7 +124,7 @@ func newAppLiveObj(status health.HealthStatusCode) *unstructured.Unstructured { }, TypeMeta: metav1.TypeMeta{ APIVersion: "argoproj.io/v1alpha1", - Kind: "Application", + Kind: application.ApplicationKind, }, Status: appv1.ApplicationStatus{ Health: appv1.HealthStatus{ 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/metrics/metrics.go b/controller/metrics/metrics.go index 3cd9837ff7036..94405b51eac75 100644 --- a/controller/metrics/metrics.go +++ b/controller/metrics/metrics.go @@ -17,11 +17,14 @@ import ( log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/labels" + "github.com/argoproj/argo-cd/v2/common" argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" applister "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1" "github.com/argoproj/argo-cd/v2/util/git" "github.com/argoproj/argo-cd/v2/util/healthz" "github.com/argoproj/argo-cd/v2/util/profile" + + ctrl_metrics "sigs.k8s.io/controller-runtime/pkg/metrics" ) type MetricsServer struct { @@ -56,7 +59,7 @@ var ( descAppInfo = prometheus.NewDesc( "argocd_app_info", "Information about application.", - append(descAppDefaultLabels, "repo", "dest_server", "dest_namespace", "sync_status", "health_status", "operation"), + append(descAppDefaultLabels, "autosync_enabled", "repo", "dest_server", "dest_namespace", "sync_status", "health_status", "operation"), nil, ) // DEPRECATED @@ -159,12 +162,12 @@ func NewMetricsServer(addr string, appLister applister.ApplicationLister, appFil mux := http.NewServeMux() registry := NewAppRegistry(appLister, appFilter, appLabels) - registry.MustRegister(depth, adds, latency, workDuration, unfinished, longestRunningProcessor, retries) + mux.Handle(MetricsPath, promhttp.HandlerFor(prometheus.Gatherers{ // contains app controller specific metrics registry, - // contains process, golang and controller workqueues metrics - prometheus.DefaultGatherer, + // contains workqueue metrics, process and golang metrics + ctrl_metrics.Registry, }, promhttp.HandlerOpts{})) profile.RegisterProfiler(mux) healthz.ServeHealthCheck(mux, healthCheck) @@ -260,12 +263,12 @@ func (m *MetricsServer) IncKubernetesRequest(app *argoappv1.Application, server, } func (m *MetricsServer) IncRedisRequest(failed bool) { - m.redisRequestCounter.WithLabelValues(m.hostname, "argocd-application-controller", strconv.FormatBool(failed)).Inc() + m.redisRequestCounter.WithLabelValues(m.hostname, common.ApplicationController, strconv.FormatBool(failed)).Inc() } // ObserveRedisRequestDuration observes redis request duration func (m *MetricsServer) ObserveRedisRequestDuration(duration time.Duration) { - m.redisRequestHistogram.WithLabelValues(m.hostname, "argocd-application-controller").Observe(duration.Seconds()) + m.redisRequestHistogram.WithLabelValues(m.hostname, common.ApplicationController).Observe(duration.Seconds()) } // IncReconcile increments the reconcile counter for an application @@ -381,7 +384,9 @@ func (c *appCollector) collectApps(ch chan<- prometheus.Metric, app *argoappv1.A healthStatus = health.HealthStatusUnknown } - addGauge(descAppInfo, 1, git.NormalizeGitURL(app.Spec.GetSource().RepoURL), app.Spec.Destination.Server, app.Spec.Destination.Namespace, string(syncStatus), string(healthStatus), operation) + autoSyncEnabled := app.Spec.SyncPolicy != nil && app.Spec.SyncPolicy.Automated != nil + + addGauge(descAppInfo, 1, strconv.FormatBool(autoSyncEnabled), git.NormalizeGitURL(app.Spec.GetSource().RepoURL), app.Spec.Destination.Server, app.Spec.Destination.Namespace, string(syncStatus), string(healthStatus), operation) if len(c.appLabels) > 0 { labelValues := []string{} diff --git a/controller/metrics/metrics_test.go b/controller/metrics/metrics_test.go index 36a1574489719..23628c38347a5 100644 --- a/controller/metrics/metrics_test.go +++ b/controller/metrics/metrics_test.go @@ -2,26 +2,29 @@ package metrics import ( "context" + "fmt" "log" "net/http" "net/http/httptest" - "os" "strings" "testing" "time" gitopsCache "github.com/argoproj/gitops-engine/pkg/cache" "github.com/argoproj/gitops-engine/pkg/sync/common" - "github.com/ghodss/yaml" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/yaml" argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/fake" appinformer "github.com/argoproj/argo-cd/v2/pkg/client/informers/externalversions" applister "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1" + + "sigs.k8s.io/controller-runtime/pkg/controller" ) const fakeApp = ` @@ -67,6 +70,10 @@ spec: source: path: some/path repoURL: https://github.com/argoproj/argocd-example-apps.git + syncPolicy: + automated: + selfHeal: false + prune: true status: sync: status: Synced @@ -98,6 +105,10 @@ spec: source: path: some/path repoURL: https://github.com/argoproj/argocd-example-apps.git + syncPolicy: + automated: + selfHeal: true + prune: false status: sync: status: OutOfSync @@ -133,6 +144,12 @@ var appFilter = func(obj interface{}) bool { return true } +func init() { + // Create a fake controller so we initialize the internal controller metrics. + // https://github.com/kubernetes-sigs/controller-runtime/blob/4000e996a202917ad7d40f02ed8a2079a9ce25e9/pkg/internal/controller/metrics/metrics.go + _, _ = controller.New("test-controller", nil, controller.Options{}) +} + func newFakeApp(fakeAppYAML string) *argoappv1.Application { var app argoappv1.Application err := yaml.Unmarshal([]byte(fakeAppYAML), &app) @@ -207,7 +224,7 @@ func runTest(t *testing.T, cfg TestMetricServerConfig) { metricsServ.registry.MustRegister(collector) } - req, err := http.NewRequest("GET", "/metrics", nil) + req, err := http.NewRequest(http.MethodGet, "/metrics", nil) assert.NoError(t, err) rr := httptest.NewRecorder() metricsServ.Handler.ServeHTTP(rr, req) @@ -228,9 +245,9 @@ func TestMetrics(t *testing.T) { responseContains: ` # HELP argocd_app_info Information about application. # TYPE argocd_app_info gauge -argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Degraded",name="my-app-3",namespace="argocd",operation="delete",project="important-project",repo="https://github.com/argoproj/argocd-example-apps",sync_status="OutOfSync"} 1 -argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Healthy",name="my-app",namespace="argocd",operation="",project="important-project",repo="https://github.com/argoproj/argocd-example-apps",sync_status="Synced"} 1 -argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Healthy",name="my-app-2",namespace="argocd",operation="sync",project="important-project",repo="https://github.com/argoproj/argocd-example-apps",sync_status="Synced"} 1 +argocd_app_info{autosync_enabled="true",dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Degraded",name="my-app-3",namespace="argocd",operation="delete",project="important-project",repo="https://github.com/argoproj/argocd-example-apps",sync_status="OutOfSync"} 1 +argocd_app_info{autosync_enabled="false",dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Healthy",name="my-app",namespace="argocd",operation="",project="important-project",repo="https://github.com/argoproj/argocd-example-apps",sync_status="Synced"} 1 +argocd_app_info{autosync_enabled="true",dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Healthy",name="my-app-2",namespace="argocd",operation="sync",project="important-project",repo="https://github.com/argoproj/argocd-example-apps",sync_status="Synced"} 1 `, }, { @@ -238,7 +255,7 @@ argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost: responseContains: ` # HELP argocd_app_info Information about application. # TYPE argocd_app_info gauge -argocd_app_info{dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Healthy",name="my-app",namespace="argocd",operation="",project="default",repo="https://github.com/argoproj/argocd-example-apps",sync_status="Synced"} 1 +argocd_app_info{autosync_enabled="false",dest_namespace="dummy-namespace",dest_server="https://localhost:6443",health_status="Healthy",name="my-app",namespace="argocd",operation="",project="default",repo="https://github.com/argoproj/argocd-example-apps",sync_status="Synced"} 1 `, }, } @@ -292,8 +309,7 @@ argocd_app_labels{label_non_existing="",name="my-app-3",namespace="argocd",proje } func TestLegacyMetrics(t *testing.T) { - os.Setenv(EnvVarLegacyControllerMetrics, "true") - defer os.Unsetenv(EnvVarLegacyControllerMetrics) + t.Setenv(EnvVarLegacyControllerMetrics, "true") expectedResponse := ` # HELP argocd_app_created_time Creation time in unix timestamp for an application. @@ -337,7 +353,7 @@ argocd_app_sync_total{dest_server="https://localhost:6443",name="my-app",namespa metricsServ.IncSync(fakeApp, &argoappv1.OperationState{Phase: common.OperationSucceeded}) metricsServ.IncSync(fakeApp, &argoappv1.OperationState{Phase: common.OperationSucceeded}) - req, err := http.NewRequest("GET", "/metrics", nil) + req, err := http.NewRequest(http.MethodGet, "/metrics", nil) assert.NoError(t, err) rr := httptest.NewRecorder() metricsServ.Handler.ServeHTTP(rr, req) @@ -354,7 +370,7 @@ func assertMetricsPrinted(t *testing.T, expectedLines, body string) { if line == "" { continue } - assert.Contains(t, body, line, "expected metrics mismatch") + assert.Contains(t, body, line, fmt.Sprintf("expected metrics mismatch for line: %s", line)) } } @@ -391,7 +407,7 @@ argocd_app_reconcile_count{dest_server="https://localhost:6443",namespace="argoc fakeApp := newFakeApp(fakeApp) metricsServ.IncReconcile(fakeApp, 5*time.Second) - req, err := http.NewRequest("GET", "/metrics", nil) + req, err := http.NewRequest(http.MethodGet, "/metrics", nil) assert.NoError(t, err) rr := httptest.NewRecorder() metricsServ.Handler.ServeHTTP(rr, req) @@ -415,7 +431,7 @@ argocd_app_sync_total{dest_server="https://localhost:6443",name="my-app",namespa argocd_app_sync_total{dest_server="https://localhost:6443",name="my-app",namespace="argocd",phase="Succeeded",project="important-project"} 2 ` - req, err := http.NewRequest("GET", "/metrics", nil) + req, err := http.NewRequest(http.MethodGet, "/metrics", nil) assert.NoError(t, err) rr := httptest.NewRecorder() metricsServ.Handler.ServeHTTP(rr, req) @@ -426,7 +442,7 @@ argocd_app_sync_total{dest_server="https://localhost:6443",name="my-app",namespa err = metricsServ.SetExpiration(time.Second) assert.NoError(t, err) time.Sleep(2 * time.Second) - req, err = http.NewRequest("GET", "/metrics", nil) + req, err = http.NewRequest(http.MethodGet, "/metrics", nil) assert.NoError(t, err) rr = httptest.NewRecorder() metricsServ.Handler.ServeHTTP(rr, req) @@ -437,3 +453,70 @@ argocd_app_sync_total{dest_server="https://localhost:6443",name="my-app",namespa err = metricsServ.SetExpiration(time.Second) assert.Error(t, err) } + +func TestWorkqueueMetrics(t *testing.T) { + cancel, appLister := newFakeLister() + defer cancel() + metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{}) + assert.NoError(t, err) + + expectedMetrics := ` +# TYPE workqueue_adds_total counter +workqueue_adds_total{name="test"} + +# TYPE workqueue_depth gauge +workqueue_depth{name="test"} + +# TYPE workqueue_longest_running_processor_seconds gauge +workqueue_longest_running_processor_seconds{name="test"} + +# TYPE workqueue_queue_duration_seconds histogram + +# TYPE workqueue_unfinished_work_seconds gauge +workqueue_unfinished_work_seconds{name="test"} + +# TYPE workqueue_work_duration_seconds histogram +` + workqueue.NewNamed("test") + + req, err := http.NewRequest(http.MethodGet, "/metrics", nil) + assert.NoError(t, err) + rr := httptest.NewRecorder() + metricsServ.Handler.ServeHTTP(rr, req) + assert.Equal(t, rr.Code, http.StatusOK) + body := rr.Body.String() + log.Println(body) + assertMetricsPrinted(t, expectedMetrics, body) +} + +func TestGoMetrics(t *testing.T) { + cancel, appLister := newFakeLister() + defer cancel() + metricsServ, err := NewMetricsServer("localhost:8082", appLister, appFilter, noOpHealthCheck, []string{}) + assert.NoError(t, err) + + expectedMetrics := ` +# TYPE go_gc_duration_seconds summary +go_gc_duration_seconds_sum +go_gc_duration_seconds_count +# TYPE go_goroutines gauge +go_goroutines +# TYPE go_info gauge +go_info +# TYPE go_memstats_alloc_bytes gauge +go_memstats_alloc_bytes +# TYPE go_memstats_sys_bytes gauge +go_memstats_sys_bytes +# TYPE go_threads gauge +go_threads +` + + req, err := http.NewRequest(http.MethodGet, "/metrics", nil) + assert.NoError(t, err) + rr := httptest.NewRecorder() + metricsServ.Handler.ServeHTTP(rr, req) + assert.Equal(t, rr.Code, http.StatusOK) + body := rr.Body.String() + log.Println(body) + assertMetricsPrinted(t, expectedMetrics, body) +} diff --git a/controller/metrics/workqueue.go b/controller/metrics/workqueue.go deleted file mode 100644 index 2ef10685ee47d..0000000000000 --- a/controller/metrics/workqueue.go +++ /dev/null @@ -1,101 +0,0 @@ -package metrics - -import ( - "github.com/prometheus/client_golang/prometheus" - "k8s.io/client-go/util/workqueue" -) - -const ( - WorkQueueSubsystem = "workqueue" - DepthKey = "depth" - AddsKey = "adds_total" - QueueLatencyKey = "queue_duration_seconds" - WorkDurationKey = "work_duration_seconds" - UnfinishedWorkKey = "unfinished_work_seconds" - LongestRunningProcessorKey = "longest_running_processor_seconds" - RetriesKey = "retries_total" -) - -var ( - depth = prometheus.NewGaugeVec(prometheus.GaugeOpts{ - Subsystem: WorkQueueSubsystem, - Name: DepthKey, - Help: "Current depth of workqueue", - }, []string{"name"}) - - adds = prometheus.NewCounterVec(prometheus.CounterOpts{ - Subsystem: WorkQueueSubsystem, - Name: AddsKey, - Help: "Total number of adds handled by workqueue", - }, []string{"name"}) - - latency = prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Subsystem: WorkQueueSubsystem, - Name: QueueLatencyKey, - Help: "How long in seconds an item stays in workqueue before being requested", - Buckets: []float64{1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1, 5, 10, 15, 30, 60, 120, 180}, - }, []string{"name"}) - - workDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Subsystem: WorkQueueSubsystem, - Name: WorkDurationKey, - Help: "How long in seconds processing an item from workqueue takes.", - Buckets: []float64{1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, 1, 5, 10, 15, 30, 60, 120, 180}, - }, []string{"name"}) - - unfinished = prometheus.NewGaugeVec(prometheus.GaugeOpts{ - Subsystem: WorkQueueSubsystem, - Name: UnfinishedWorkKey, - Help: "How many seconds of work has been done that " + - "is in progress and hasn't been observed by work_duration. Large " + - "values indicate stuck threads. One can deduce the number of stuck " + - "threads by observing the rate at which this increases.", - }, []string{"name"}) - - longestRunningProcessor = prometheus.NewGaugeVec(prometheus.GaugeOpts{ - Subsystem: WorkQueueSubsystem, - Name: LongestRunningProcessorKey, - Help: "How many seconds has the longest running " + - "processor for workqueue been running.", - }, []string{"name"}) - - retries = prometheus.NewCounterVec(prometheus.CounterOpts{ - Subsystem: WorkQueueSubsystem, - Name: RetriesKey, - Help: "Total number of retries handled by workqueue", - }, []string{"name"}) -) - -func init() { - workqueue.SetProvider(workqueueMetricsProvider{}) -} - -type workqueueMetricsProvider struct{} - -func (workqueueMetricsProvider) NewDepthMetric(name string) workqueue.GaugeMetric { - return depth.WithLabelValues(name) -} - -func (workqueueMetricsProvider) NewAddsMetric(name string) workqueue.CounterMetric { - return adds.WithLabelValues(name) -} - -func (workqueueMetricsProvider) NewLatencyMetric(name string) workqueue.HistogramMetric { - return latency.WithLabelValues(name) -} - -func (workqueueMetricsProvider) NewWorkDurationMetric(name string) workqueue.HistogramMetric { - return workDuration.WithLabelValues(name) -} - -func (workqueueMetricsProvider) NewUnfinishedWorkSecondsMetric(name string) workqueue.SettableGaugeMetric { - return unfinished.WithLabelValues(name) -} - -func (workqueueMetricsProvider) NewLongestRunningProcessorSecondsMetric(name string) workqueue.SettableGaugeMetric { - return longestRunningProcessor.WithLabelValues(name) -} - -func (workqueueMetricsProvider) NewRetriesMetric(name string) workqueue.CounterMetric { - return retries.WithLabelValues(name) -} diff --git a/controller/sharding/cache.go b/controller/sharding/cache.go new file mode 100644 index 0000000000000..2f3ffcbcb95c6 --- /dev/null +++ b/controller/sharding/cache.go @@ -0,0 +1,264 @@ +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, apps *v1alpha1.ApplicationList) + Add(c *v1alpha1.Cluster) + Delete(clusterServer string) + Update(oldCluster *v1alpha1.Cluster, newCluster *v1alpha1.Cluster) + AddApp(a *v1alpha1.Application) + DeleteApp(a *v1alpha1.Application) + UpdateApp(a *v1alpha1.Application) + IsManagedCluster(c *v1alpha1.Cluster) bool + GetDistribution() map[string]int + GetAppDistribution() map[string]int +} + +type ClusterSharding struct { + Shard int + Replicas int + Shards map[string]int + Clusters map[string]*v1alpha1.Cluster + Apps map[string]*v1alpha1.Application + lock sync.RWMutex + getClusterShard DistributionFunction +} + +func NewClusterSharding(_ 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), + Apps: make(map[string]*v1alpha1.Application), + } + distributionFunction := NoShardingDistributionFunction() + if replicas > 1 { + log.Debugf("Processing clusters from shard %d: Using filter function: %s", shard, shardingAlgorithm) + distributionFunction = GetDistributionFunction(clusterSharding.getClusterAccessor(), clusterSharding.getAppAccessor(), 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, apps *v1alpha1.ApplicationList) { + sharding.lock.Lock() + defer sharding.lock.Unlock() + newClusters := make(map[string]*v1alpha1.Cluster, len(clusters.Items)) + for _, c := range clusters.Items { + cluster := c + newClusters[c.Server] = &cluster + } + sharding.Clusters = newClusters + + newApps := make(map[string]*v1alpha1.Application, len(apps.Items)) + for i := range apps.Items { + app := apps.Items[i] + newApps[app.Name] = &app + } + sharding.Apps = newApps + 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(oldCluster *v1alpha1.Cluster, newCluster *v1alpha1.Cluster) { + sharding.lock.Lock() + defer sharding.lock.Unlock() + + if _, ok := sharding.Clusters[oldCluster.Server]; ok && oldCluster.Server != newCluster.Server { + delete(sharding.Clusters, oldCluster.Server) + delete(sharding.Shards, oldCluster.Server) + } + sharding.Clusters[newCluster.Server] = newCluster + if hasShardingUpdates(oldCluster, newCluster) { + sharding.updateDistribution() + } else { + log.Debugf("Skipping sharding distribution update. No relevant changes") + } +} + +func (sharding *ClusterSharding) GetDistribution() map[string]int { + sharding.lock.RLock() + defer sharding.lock.RUnlock() + shards := sharding.Shards + + distribution := make(map[string]int, len(shards)) + for k, v := range shards { + distribution[k] = v + } + return distribution +} + +func (sharding *ClusterSharding) updateDistribution() { + for k, 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) + } + + existingShard, ok := sharding.Shards[k] + if ok && existingShard != shard { + log.Infof("Cluster %s has changed shard from %d to %d", k, existingShard, shard) + } else if !ok { + log.Infof("Cluster %s has been assigned to shard %d", k, shard) + } else { + log.Debugf("Cluster %s has not changed shard", k) + } + sharding.Shards[k] = shard + } +} + +// hasShardingUpdates returns true if the sharding distribution has explicitly changed +func hasShardingUpdates(old, new *v1alpha1.Cluster) bool { + if old == nil || new == nil { + return false + } + + // returns true if the cluster id has changed because some sharding algorithms depend on it. + if old.ID != new.ID { + return true + } + + if old.Server != new.Server { + return true + } + + // return false if the shard field has not been modified + if old.Shard == nil && new.Shard == nil { + return false + } + return old.Shard == nil || new.Shard == nil || int64(*old.Shard) != int64(*new.Shard) +} + +// A read lock should be acquired before calling getClusterAccessor. +func (d *ClusterSharding) getClusterAccessor() clusterAccessor { + return func() []*v1alpha1.Cluster { + // no need to lock, as this is only called from the updateDistribution function + clusters := make([]*v1alpha1.Cluster, 0, len(d.Clusters)) + for _, c := range d.Clusters { + clusters = append(clusters, c) + } + return clusters + } +} + +// A read lock should be acquired before calling getAppAccessor. +func (d *ClusterSharding) getAppAccessor() appAccessor { + return func() []*v1alpha1.Application { + apps := make([]*v1alpha1.Application, 0, len(d.Apps)) + for _, a := range d.Apps { + apps = append(apps, a) + } + return apps + } +} + +func (sharding *ClusterSharding) AddApp(a *v1alpha1.Application) { + sharding.lock.Lock() + defer sharding.lock.Unlock() + + _, ok := sharding.Apps[a.Name] + sharding.Apps[a.Name] = a + if !ok { + sharding.updateDistribution() + } else { + log.Debugf("Skipping sharding distribution update. App already added") + } +} + +func (sharding *ClusterSharding) DeleteApp(a *v1alpha1.Application) { + sharding.lock.Lock() + defer sharding.lock.Unlock() + if _, ok := sharding.Apps[a.Name]; ok { + delete(sharding.Apps, a.Name) + sharding.updateDistribution() + } +} + +func (sharding *ClusterSharding) UpdateApp(a *v1alpha1.Application) { + sharding.lock.Lock() + defer sharding.lock.Unlock() + + _, ok := sharding.Apps[a.Name] + sharding.Apps[a.Name] = a + if !ok { + sharding.updateDistribution() + } else { + log.Debugf("Skipping sharding distribution update. No relevant changes") + } +} + +// GetAppDistribution should be not be called from a DestributionFunction because +// it could cause a deadlock when updateDistribution is called. +func (sharding *ClusterSharding) GetAppDistribution() map[string]int { + sharding.lock.RLock() + clusters := sharding.Clusters + apps := sharding.Apps + sharding.lock.RUnlock() + + appDistribution := make(map[string]int, len(clusters)) + + for _, a := range apps { + if _, ok := appDistribution[a.Spec.Destination.Server]; !ok { + appDistribution[a.Spec.Destination.Server] = 0 + } + appDistribution[a.Spec.Destination.Server]++ + } + return appDistribution +} diff --git a/controller/sharding/cache_test.go b/controller/sharding/cache_test.go new file mode 100644 index 0000000000000..f7798c31e3608 --- /dev/null +++ b/controller/sharding/cache_test.go @@ -0,0 +1,511 @@ +package sharding + +import ( + "testing" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks" + "github.com/stretchr/testify/assert" +) + +func setupTestSharding(shard int, replicas int) *ClusterSharding { + shardingAlgorithm := "legacy" // we are using the legacy algorithm as it is deterministic based on the cluster id which is easier to test + db := &dbmocks.ArgoDB{} + return NewClusterSharding(db, shard, replicas, shardingAlgorithm).(*ClusterSharding) +} + +func TestNewClusterSharding(t *testing.T) { + shard := 1 + replicas := 2 + sharding := setupTestSharding(shard, replicas) + + assert.NotNil(t, sharding) + assert.Equal(t, shard, sharding.Shard) + assert.Equal(t, replicas, sharding.Replicas) + assert.NotNil(t, sharding.Shards) + assert.NotNil(t, sharding.Clusters) +} + +func TestClusterSharding_Add(t *testing.T) { + shard := 1 + replicas := 2 + sharding := setupTestSharding(shard, replicas) + + clusterA := &v1alpha1.Cluster{ + ID: "2", + Server: "https://127.0.0.1:6443", + } + + sharding.Add(clusterA) + + clusterB := v1alpha1.Cluster{ + ID: "1", + Server: "https://kubernetes.default.svc", + } + + sharding.Add(&clusterB) + + distribution := sharding.GetDistribution() + + assert.Contains(t, sharding.Clusters, clusterA.Server) + assert.Contains(t, sharding.Clusters, clusterB.Server) + + clusterDistribution, ok := distribution[clusterA.Server] + assert.True(t, ok) + assert.Equal(t, 1, clusterDistribution) + + myClusterDistribution, ok := distribution[clusterB.Server] + assert.True(t, ok) + assert.Equal(t, 0, myClusterDistribution) + + assert.Equal(t, 2, len(distribution)) +} + +func TestClusterSharding_AddRoundRobin_Redistributes(t *testing.T) { + shard := 1 + replicas := 2 + + db := &dbmocks.ArgoDB{} + + sharding := NewClusterSharding(db, shard, replicas, "round-robin").(*ClusterSharding) + + clusterA := &v1alpha1.Cluster{ + ID: "1", + Server: "https://127.0.0.1:6443", + } + sharding.Add(clusterA) + + clusterB := v1alpha1.Cluster{ + ID: "3", + Server: "https://kubernetes.default.svc", + } + sharding.Add(&clusterB) + + distributionBefore := sharding.GetDistribution() + + assert.Contains(t, sharding.Clusters, clusterA.Server) + assert.Contains(t, sharding.Clusters, clusterB.Server) + + clusterDistributionA, ok := distributionBefore[clusterA.Server] + assert.True(t, ok) + assert.Equal(t, 0, clusterDistributionA) + + clusterDistributionB, ok := distributionBefore[clusterB.Server] + assert.True(t, ok) + assert.Equal(t, 1, clusterDistributionB) + + assert.Equal(t, 2, len(distributionBefore)) + + clusterC := v1alpha1.Cluster{ + ID: "2", + Server: "https://1.1.1.1", + } + sharding.Add(&clusterC) + + distributionAfter := sharding.GetDistribution() + + assert.Contains(t, sharding.Clusters, clusterA.Server) + assert.Contains(t, sharding.Clusters, clusterB.Server) + assert.Contains(t, sharding.Clusters, clusterC.Server) + + clusterDistributionA, ok = distributionAfter[clusterA.Server] + assert.True(t, ok) + assert.Equal(t, 0, clusterDistributionA) + + clusterDistributionC, ok := distributionAfter[clusterC.Server] + assert.True(t, ok) + assert.Equal(t, 1, clusterDistributionC) // will be assigned to shard 1 because the .ID is smaller then the "B" cluster + + clusterDistributionB, ok = distributionAfter[clusterB.Server] + assert.True(t, ok) + assert.Equal(t, 0, clusterDistributionB) // will be reassigned to shard 0 because the .ID is bigger then the "C" cluster +} + +func TestClusterSharding_Delete(t *testing.T) { + shard := 1 + replicas := 2 + sharding := setupTestSharding(shard, replicas) + + sharding.Init( + &v1alpha1.ClusterList{ + Items: []v1alpha1.Cluster{ + { + ID: "2", + Server: "https://127.0.0.1:6443", + }, + { + ID: "1", + Server: "https://kubernetes.default.svc", + }, + }, + }, + &v1alpha1.ApplicationList{ + Items: []v1alpha1.Application{ + createApp("app2", "https://127.0.0.1:6443"), + createApp("app1", "https://kubernetes.default.svc"), + }, + }, + ) + + sharding.Delete("https://kubernetes.default.svc") + distribution := sharding.GetDistribution() + assert.Equal(t, 1, len(distribution)) +} + +func TestClusterSharding_Update(t *testing.T) { + shard := 1 + replicas := 2 + sharding := setupTestSharding(shard, replicas) + + sharding.Init( + &v1alpha1.ClusterList{ + Items: []v1alpha1.Cluster{ + { + ID: "2", + Server: "https://127.0.0.1:6443", + }, + { + ID: "1", + Server: "https://kubernetes.default.svc", + }, + }, + }, + &v1alpha1.ApplicationList{ + Items: []v1alpha1.Application{ + createApp("app2", "https://127.0.0.1:6443"), + createApp("app1", "https://kubernetes.default.svc"), + }, + }, + ) + + distributionBefore := sharding.GetDistribution() + assert.Equal(t, 2, len(distributionBefore)) + + distributionA, ok := distributionBefore["https://kubernetes.default.svc"] + assert.True(t, ok) + assert.Equal(t, 0, distributionA) + + sharding.Update(&v1alpha1.Cluster{ + ID: "1", + Server: "https://kubernetes.default.svc", + }, &v1alpha1.Cluster{ + ID: "4", + Server: "https://kubernetes.default.svc", + }) + + distributionAfter := sharding.GetDistribution() + assert.Equal(t, 2, len(distributionAfter)) + + distributionA, ok = distributionAfter["https://kubernetes.default.svc"] + assert.True(t, ok) + assert.Equal(t, 1, distributionA) +} + +func TestClusterSharding_UpdateServerName(t *testing.T) { + shard := 1 + replicas := 2 + sharding := setupTestSharding(shard, replicas) + + sharding.Init( + &v1alpha1.ClusterList{ + Items: []v1alpha1.Cluster{ + { + ID: "2", + Server: "https://127.0.0.1:6443", + }, + { + ID: "1", + Server: "https://kubernetes.default.svc", + }, + }, + }, + &v1alpha1.ApplicationList{ + Items: []v1alpha1.Application{ + createApp("app2", "https://127.0.0.1:6443"), + createApp("app1", "https://kubernetes.default.svc"), + }, + }, + ) + + distributionBefore := sharding.GetDistribution() + assert.Equal(t, 2, len(distributionBefore)) + + distributionA, ok := distributionBefore["https://kubernetes.default.svc"] + assert.True(t, ok) + assert.Equal(t, 0, distributionA) + + sharding.Update(&v1alpha1.Cluster{ + ID: "1", + Server: "https://kubernetes.default.svc", + }, &v1alpha1.Cluster{ + ID: "1", + Server: "https://server2", + }) + + distributionAfter := sharding.GetDistribution() + assert.Equal(t, 2, len(distributionAfter)) + + _, ok = distributionAfter["https://kubernetes.default.svc"] + assert.False(t, ok) // the old server name should not be present anymore + + _, ok = distributionAfter["https://server2"] + assert.True(t, ok) // the new server name should be present +} + +func TestClusterSharding_IsManagedCluster(t *testing.T) { + replicas := 2 + sharding0 := setupTestSharding(0, replicas) + + sharding0.Init( + &v1alpha1.ClusterList{ + Items: []v1alpha1.Cluster{ + { + ID: "1", + Server: "https://kubernetes.default.svc", + }, + { + ID: "2", + Server: "https://127.0.0.1:6443", + }, + }, + }, + &v1alpha1.ApplicationList{ + Items: []v1alpha1.Application{ + createApp("app2", "https://127.0.0.1:6443"), + createApp("app1", "https://kubernetes.default.svc"), + }, + }, + ) + + assert.True(t, sharding0.IsManagedCluster(&v1alpha1.Cluster{ + ID: "1", + Server: "https://kubernetes.default.svc", + })) + + assert.False(t, sharding0.IsManagedCluster(&v1alpha1.Cluster{ + ID: "2", + Server: "https://127.0.0.1:6443", + })) + + sharding1 := setupTestSharding(1, replicas) + + sharding1.Init( + &v1alpha1.ClusterList{ + Items: []v1alpha1.Cluster{ + { + ID: "2", + Server: "https://127.0.0.1:6443", + }, + { + ID: "1", + Server: "https://kubernetes.default.svc", + }, + }, + }, + &v1alpha1.ApplicationList{ + Items: []v1alpha1.Application{ + createApp("app2", "https://127.0.0.1:6443"), + createApp("app1", "https://kubernetes.default.svc"), + }, + }, + ) + + assert.False(t, sharding1.IsManagedCluster(&v1alpha1.Cluster{ + ID: "1", + Server: "https://kubernetes.default.svc", + })) + + assert.True(t, sharding1.IsManagedCluster(&v1alpha1.Cluster{ + ID: "2", + Server: "https://127.0.0.1:6443", + })) + +} + +func TestClusterSharding_ClusterShardOfResourceShouldNotBeChanged(t *testing.T) { + shard := 1 + replicas := 2 + sharding := setupTestSharding(shard, replicas) + + Int64Ptr := func(i int64) *int64 { + return &i + } + + clusterWithNil := &v1alpha1.Cluster{ + ID: "2", + Server: "https://127.0.0.1:6443", + Shard: nil, + } + + clusterWithValue := &v1alpha1.Cluster{ + ID: "1", + Server: "https://kubernetes.default.svc", + Shard: Int64Ptr(1), + } + + clusterWithToBigValue := &v1alpha1.Cluster{ + ID: "3", + Server: "https://1.1.1.1", + Shard: Int64Ptr(999), // shard value is explicitly bigger than the number of replicas + } + + sharding.Init( + &v1alpha1.ClusterList{ + Items: []v1alpha1.Cluster{ + *clusterWithNil, + *clusterWithValue, + *clusterWithToBigValue, + }, + }, + &v1alpha1.ApplicationList{ + Items: []v1alpha1.Application{ + createApp("app2", "https://127.0.0.1:6443"), + createApp("app1", "https://kubernetes.default.svc"), + }, + }, + ) + distribution := sharding.GetDistribution() + assert.Equal(t, 3, len(distribution)) + + assert.Nil(t, sharding.Clusters[clusterWithNil.Server].Shard) + + assert.NotNil(t, sharding.Clusters[clusterWithValue.Server].Shard) + assert.Equal(t, int64(1), *sharding.Clusters[clusterWithValue.Server].Shard) + assert.Equal(t, 1, distribution[clusterWithValue.Server]) + + assert.NotNil(t, sharding.Clusters[clusterWithToBigValue.Server].Shard) + assert.Equal(t, int64(999), *sharding.Clusters[clusterWithToBigValue.Server].Shard) + assert.Equal(t, 0, distribution[clusterWithToBigValue.Server]) // will be assigned to shard 0 because the value is bigger than the number of replicas +} + +func TestHasShardingUpdates(t *testing.T) { + Int64Ptr := func(i int64) *int64 { + return &i + } + + testCases := []struct { + name string + old *v1alpha1.Cluster + new *v1alpha1.Cluster + expected bool + }{ + { + name: "No updates", + old: &v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Shard: Int64Ptr(1), + }, + new: &v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Shard: Int64Ptr(1), + }, + expected: false, + }, + { + name: "Updates", + old: &v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Shard: Int64Ptr(1), + }, + new: &v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Shard: Int64Ptr(2), + }, + expected: true, + }, + { + name: "Old is nil", + old: nil, + new: &v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Shard: Int64Ptr(2), + }, + expected: false, + }, + { + name: "New is nil", + old: &v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Shard: Int64Ptr(2), + }, + new: nil, + expected: false, + }, + { + name: "Both are nil", + old: nil, + new: nil, + expected: false, + }, + { + name: "Both shards are nil", + old: &v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Shard: nil, + }, + new: &v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Shard: nil, + }, + expected: false, + }, + { + name: "Old shard is nil", + old: &v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Shard: nil, + }, + new: &v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Shard: Int64Ptr(2), + }, + expected: true, + }, + { + name: "New shard is nil", + old: &v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Shard: Int64Ptr(2), + }, + new: &v1alpha1.Cluster{ + Server: "https://kubernetes.default.svc", + Shard: nil, + }, + expected: true, + }, + { + name: "Cluster ID has changed", + old: &v1alpha1.Cluster{ + ID: "1", + Server: "https://kubernetes.default.svc", + Shard: Int64Ptr(2), + }, + new: &v1alpha1.Cluster{ + ID: "2", + Server: "https://kubernetes.default.svc", + Shard: Int64Ptr(2), + }, + expected: true, + }, + { + name: "Server has changed", + old: &v1alpha1.Cluster{ + ID: "1", + Server: "https://server1", + Shard: Int64Ptr(2), + }, + new: &v1alpha1.Cluster{ + ID: "1", + Server: "https://server2", + Shard: Int64Ptr(2), + }, + expected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + assert.Equal(t, tc.expected, hasShardingUpdates(tc.old, tc.new)) + }) + } +} diff --git a/controller/sharding/sharding.go b/controller/sharding/sharding.go index 1c0615196bd06..e4af7010931c6 100644 --- a/controller/sharding/sharding.go +++ b/controller/sharding/sharding.go @@ -1,53 +1,424 @@ package sharding import ( + "context" "fmt" "hash/fnv" + "math" "os" + "sort" "strconv" "strings" + "time" + "encoding/json" + + "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + + "github.com/argoproj/argo-cd/v2/util/db" + "github.com/argoproj/argo-cd/v2/util/env" + "github.com/argoproj/argo-cd/v2/util/errors" + "github.com/argoproj/argo-cd/v2/util/settings" + log "github.com/sirupsen/logrus" + kubeerrors "k8s.io/apimachinery/pkg/api/errors" ) +// Make it overridable for testing +var osHostnameFunction = os.Hostname + +// Make it overridable for testing +var heartbeatCurrentTime = metav1.Now + +var ( + HeartbeatDuration = env.ParseNumFromEnv(common.EnvControllerHeartbeatTime, 10, 10, 60) + HeartbeatTimeout = 3 * HeartbeatDuration +) + +const ShardControllerMappingKey = "shardControllerMapping" + +type DistributionFunction func(c *v1alpha1.Cluster) int +type ClusterFilterFunction func(c *v1alpha1.Cluster) bool +type clusterAccessor func() []*v1alpha1.Cluster +type appAccessor func() []*v1alpha1.Application + +// 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. +type shardApplicationControllerMapping struct { + ShardNumber int + ControllerName string + HeartbeatTime metav1.Time +} + +// GetClusterFilter returns a ClusterFilterFunction which is a function taking a cluster as a parameter +// 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, replicas, shard int) ClusterFilterFunction { + return func(c *v1alpha1.Cluster) bool { + clusterShard := 0 + if c != nil && c.Shard != nil { + requestedShard := int(*c.Shard) + if requestedShard < replicas { + clusterShard = requestedShard + } else { + log.Warnf("Specified cluster shard (%d) for cluster: %s is greater than the number of available shard. Assigning automatically.", requestedShard, c.Name) + } + } else { + clusterShard = distributionFunction(c) + } + return clusterShard == shard + } +} + +// GetDistributionFunction returns which DistributionFunction should be used based on the passed algorithm and +// the current datas. +func GetDistributionFunction(clusters clusterAccessor, apps appAccessor, shardingAlgorithm string, replicasCount int) DistributionFunction { + log.Debugf("Using filter function: %s", shardingAlgorithm) + distributionFunction := LegacyDistributionFunction(replicasCount) + switch shardingAlgorithm { + case common.RoundRobinShardingAlgorithm: + distributionFunction = RoundRobinDistributionFunction(clusters, replicasCount) + case common.LegacyShardingAlgorithm: + distributionFunction = LegacyDistributionFunction(replicasCount) + default: + log.Warnf("distribution type %s is not supported, defaulting to %s", shardingAlgorithm, common.DefaultShardingAlgorithm) + } + return distributionFunction +} + +// LegacyDistributionFunction returns a DistributionFunction using a stable distribution algorithm: +// for a given cluster the function will return the shard number based on the cluster id. This function +// 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(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 == "" { + return 0 + } else { + h := fnv.New32a() + _, _ = h.Write([]byte(id)) + shard := int32(h.Sum32() % uint32(replicas)) + log.Debugf("Cluster with id=%s will be processed by shard %d", id, shard) + return int(shard) + } + } +} + +// RoundRobinDistributionFunction returns a DistributionFunction using an homogeneous distribution algorithm: +// for a given cluster the function will return the shard number based on the modulo of the cluster rank in +// the cluster's list sorted by uid on the shard number. +// 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(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(clusters) + clusterIndex, ok := clusterIndexdByClusterIdMap[c.ID] + if !ok { + log.Warnf("Cluster with id=%s not found in cluster map.", c.ID) + return -1 + } + shard := int(clusterIndex % replicas) + log.Debugf("Cluster with id=%s will be processed by shard %d", c.ID, shard) + return shard + } + } + log.Warnf("The number of replicas (%d) is lower than 1", replicas) + return -1 + } +} + +// 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 := os.Hostname() + hostname, err := osHostnameFunction() if err != nil { - return 0, err + return -1, err } 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 shard, nil + return int(shard), nil +} + +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 } -// GetShardByID calculates cluster shard as `clusterSecret.UID % replicas count` -func GetShardByID(id string, replicas int) int { - if id == "" { - return 0 +func createClusterIndexByClusterIdMap(getCluster clusterAccessor) map[string]int { + clusters := getSortedClustersList(getCluster) + log.Debugf("ClustersList has %d items", len(clusters)) + 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) + clusterById[cluster.ID] = cluster + clusterIndexedByClusterId[cluster.ID] = i + } + return clusterIndexedByClusterId +} + +// GetOrUpdateShardFromConfigMap finds the shard number from the shard mapping configmap. If the shard mapping configmap does not exist, +// the function creates the shard mapping configmap. +// The function takes the shard number from the environment variable (default value -1, if not set) and passes it to this function. +// 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.Interface, settingsMgr *settings.SettingsManager, replicas, shard int) (int, error) { + hostname, err := osHostnameFunction() + if err != nil { + return -1, err + } + + // fetch the shard mapping configMap + shardMappingCM, err := kubeClient.CoreV1().ConfigMaps(settingsMgr.GetNamespace()).Get(context.Background(), common.ArgoCDAppControllerShardConfigMapName, metav1.GetOptions{}) + + if err != nil { + if !kubeerrors.IsNotFound(err) { + return -1, fmt.Errorf("error getting sharding config map: %s", err) + } + log.Infof("shard mapping configmap %s not found. Creating default shard mapping configmap.", common.ArgoCDAppControllerShardConfigMapName) + + // if the shard is not set as an environment variable, set the default value of shard to 0 for generating default CM + if shard == -1 { + shard = 0 + } + shardMappingCM, err = generateDefaultShardMappingCM(settingsMgr.GetNamespace(), hostname, replicas, shard) + if err != nil { + return -1, fmt.Errorf("error generating default shard mapping configmap %s", err) + } + if _, err = kubeClient.CoreV1().ConfigMaps(settingsMgr.GetNamespace()).Create(context.Background(), shardMappingCM, metav1.CreateOptions{}); err != nil { + return -1, fmt.Errorf("error creating shard mapping configmap %s", err) + } + // return 0 as the controller is assigned to shard 0 while generating default shard mapping ConfigMap + return shard, nil } else { - h := fnv.New32a() - _, _ = h.Write([]byte(id)) - return int(h.Sum32() % uint32(replicas)) + // Identify the available shard and update the ConfigMap + data := shardMappingCM.Data[ShardControllerMappingKey] + var shardMappingData []shardApplicationControllerMapping + err := json.Unmarshal([]byte(data), &shardMappingData) + if err != nil { + return -1, fmt.Errorf("error unmarshalling shard config map data: %s", err) + } + + shard, shardMappingData := getOrUpdateShardNumberForController(shardMappingData, hostname, replicas, shard) + updatedShardMappingData, err := json.Marshal(shardMappingData) + if err != nil { + return -1, fmt.Errorf("error marshalling data of shard mapping ConfigMap: %s", err) + } + shardMappingCM.Data[ShardControllerMappingKey] = string(updatedShardMappingData) + + _, err = kubeClient.CoreV1().ConfigMaps(settingsMgr.GetNamespace()).Update(context.Background(), shardMappingCM, metav1.UpdateOptions{}) + if err != nil { + return -1, err + } + return shard, nil } } -func GetClusterFilter(replicas int, shard int) func(c *v1alpha1.Cluster) bool { - return func(c *v1alpha1.Cluster) bool { - clusterShard := 0 - // cluster might be nil if app is using invalid cluster URL, assume shard 0 in this case. - if c != nil { - if c.Shard != nil { - clusterShard = int(*c.Shard) - } else { - clusterShard = GetShardByID(c.ID, replicas) +// getOrUpdateShardNumberForController takes list of shardApplicationControllerMapping and performs computation to find the matching or empty shard number +func getOrUpdateShardNumberForController(shardMappingData []shardApplicationControllerMapping, hostname string, replicas, shard int) (int, []shardApplicationControllerMapping) { + + // if current length of shardMappingData in shard mapping configMap is less than the number of replicas, + // create additional empty entries for missing shard numbers in shardMappingDataconfigMap + if len(shardMappingData) < replicas { + // generate extra default mappings + for currentShard := len(shardMappingData); currentShard < replicas; currentShard++ { + shardMappingData = append(shardMappingData, shardApplicationControllerMapping{ + ShardNumber: currentShard, + }) + } + } + + // if current length of shardMappingData in shard mapping configMap is more than the number of replicas, + // we replace the config map with default config map and let controllers self assign the new shard to itself + if len(shardMappingData) > replicas { + shardMappingData = getDefaultShardMappingData(replicas) + } + + if shard != -1 && shard < replicas { + log.Debugf("update heartbeat for shard %d", shard) + for i := range shardMappingData { + shardMapping := shardMappingData[i] + if shardMapping.ShardNumber == shard { + log.Debugf("Shard found. Updating heartbeat!!") + shardMapping.ControllerName = hostname + shardMapping.HeartbeatTime = heartbeatCurrentTime() + shardMappingData[i] = shardMapping + break } } - return clusterShard == shard + } else { + // find the matching shard with assigned controllerName + for i := range shardMappingData { + shardMapping := shardMappingData[i] + if shardMapping.ControllerName == hostname { + log.Debugf("Shard matched. Updating heartbeat!!") + shard = int(shardMapping.ShardNumber) + shardMapping.HeartbeatTime = heartbeatCurrentTime() + shardMappingData[i] = shardMapping + break + } + } + } + + // at this point, we have still not found a shard with matching hostname. + // So, find a shard with either no controller assigned or assigned controller + // with heartbeat past threshold + if shard == -1 { + for i := range shardMappingData { + shardMapping := shardMappingData[i] + if (shardMapping.ControllerName == "") || (metav1.Now().After(shardMapping.HeartbeatTime.Add(time.Duration(HeartbeatTimeout) * time.Second))) { + shard = int(shardMapping.ShardNumber) + log.Debugf("Empty shard found %d", shard) + shardMapping.ControllerName = hostname + shardMapping.HeartbeatTime = heartbeatCurrentTime() + shardMappingData[i] = shardMapping + break + } + } + } + return shard, shardMappingData +} + +// generateDefaultShardMappingCM creates a default shard mapping configMap. Assigns current controller to shard 0. +func generateDefaultShardMappingCM(namespace, hostname string, replicas, shard int) (*v1.ConfigMap, error) { + + shardingCM := &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ArgoCDAppControllerShardConfigMapName, + Namespace: namespace, + }, + Data: map[string]string{}, + } + + shardMappingData := getDefaultShardMappingData(replicas) + + // if shard is not assigned to a controller, we use shard 0 + if shard == -1 || shard > replicas { + shard = 0 + } + shardMappingData[shard].ControllerName = hostname + shardMappingData[shard].HeartbeatTime = heartbeatCurrentTime() + + data, err := json.Marshal(shardMappingData) + if err != nil { + return nil, fmt.Errorf("error generating default ConfigMap: %s", err) + } + shardingCM.Data[ShardControllerMappingKey] = string(data) + + return shardingCM, nil +} + +func getDefaultShardMappingData(replicas int) []shardApplicationControllerMapping { + shardMappingData := make([]shardApplicationControllerMapping, 0) + + for i := 0; i < replicas; i++ { + mapping := shardApplicationControllerMapping{ + ShardNumber: i, + } + shardMappingData = append(shardMappingData, mapping) + } + return shardMappingData +} + +func GetClusterSharding(kubeClient kubernetes.Interface, settingsMgr *settings.SettingsManager, shardingAlgorithm string, enableDynamicClusterDistribution bool) (ClusterShardingCache, error) { + var replicasCount int + if enableDynamicClusterDistribution { + 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("(dynamic cluster distribution) failed to get app controller deployment: %v", err) + } + + if appControllerDeployment != nil && appControllerDeployment.Spec.Replicas != nil { + replicasCount = int(*appControllerDeployment.Spec.Replicas) + } else { + return nil, fmt.Errorf("(dynamic cluster distribution) failed to get app controller deployment replica count") + } + + } else { + replicasCount = env.ParseNumFromEnv(common.EnvControllerReplicas, 0, 0, math.MaxInt32) + } + shardNumber := env.ParseNumFromEnv(common.EnvControllerShard, -1, -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 { + 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++ { + shardNumber, err = 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 + } + log.Warnf("conflict when getting shard from shard mapping configMap. Retrying (%d/3)", i) + } + errors.CheckError(err) + } else { + if shardNumber < 0 { + var err error + shardNumber, err = 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 + } + } + } else { + log.Info("Processing all cluster shards") + shardNumber = 0 } + db := db.NewDB(settingsMgr.GetNamespace(), settingsMgr, kubeClient) + return NewClusterSharding(db, shardNumber, replicasCount, shardingAlgorithm), nil } diff --git a/controller/sharding/sharding_test.go b/controller/sharding/sharding_test.go index dc27726f8a6fa..1c338aac5f271 100644 --- a/controller/sharding/sharding_test.go +++ b/controller/sharding/sharding_test.go @@ -1,29 +1,954 @@ package sharding import ( + "context" + "encoding/json" + "errors" + "fmt" + "os" + "strconv" "testing" + "time" + "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - + dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks" + "github.com/argoproj/argo-cd/v2/util/settings" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + appsv1 "k8s.io/api/apps/v1" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + kubefake "k8s.io/client-go/kubernetes/fake" + "sigs.k8s.io/yaml" ) func TestGetShardByID_NotEmptyID(t *testing.T) { - assert.Equal(t, 0, GetShardByID("1", 2)) - assert.Equal(t, 1, GetShardByID("2", 2)) - assert.Equal(t, 0, GetShardByID("3", 2)) - assert.Equal(t, 1, GetShardByID("4", 2)) + db := &dbmocks.ArgoDB{} + 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) { - shard := GetShardByID("", 10) + db := &dbmocks.ArgoDB{} + replicasCount := 1 + db.On("GetApplicationControllerReplicas").Return(replicasCount) + distributionFunction := LegacyDistributionFunction + shard := distributionFunction(replicasCount)(&v1alpha1.Cluster{}) assert.Equal(t, 0, shard) } -func TestGetClusterFilter(t *testing.T) { - filter := GetClusterFilter(2, 1) - 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"})) +func TestGetShardByID_NoReplicas(t *testing.T) { + db := &dbmocks.ArgoDB{} + db.On("GetApplicationControllerReplicas").Return(0) + distributionFunction := LegacyDistributionFunction + shard := distributionFunction(0)(&v1alpha1.Cluster{}) + assert.Equal(t, -1, shard) +} + +func TestGetShardByID_NoReplicasUsingHashDistributionFunction(t *testing.T) { + db := &dbmocks.ArgoDB{} + db.On("GetApplicationControllerReplicas").Return(0) + distributionFunction := LegacyDistributionFunction + shard := distributionFunction(0)(&v1alpha1.Cluster{}) + assert.Equal(t, -1, shard) +} + +func TestGetShardByID_NoReplicasUsingHashDistributionFunctionWithClusters(t *testing.T) { + 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(clusters, 0) + assert.Equal(t, -1, distributionFunction(nil)) + assert.Equal(t, -1, distributionFunction(&cluster1)) + assert.Equal(t, -1, distributionFunction(&cluster2)) + assert.Equal(t, -1, distributionFunction(&cluster3)) + assert.Equal(t, -1, distributionFunction(&cluster4)) + assert.Equal(t, -1, distributionFunction(&cluster5)) +} + +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,...) + clusterAccessor, _, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() + os.Unsetenv(common.EnvControllerShardingAlgorithm) + 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,...) + clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() + replicasCount := 2 + db.On("GetApplicationControllerReplicas").Return(replicasCount) + t.Setenv(common.EnvControllerShardingAlgorithm, common.LegacyShardingAlgorithm) + 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) { + clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() + appAccessor, _, _, _, _, _ := createTestApps() + // Test with replicas set to 0 + t.Setenv(common.EnvControllerReplicas, "2") + os.Unsetenv(common.EnvControllerShardingAlgorithm) + t.Setenv(common.EnvControllerShardingAlgorithm, "unknown") + replicasCount := 2 + db.On("GetApplicationControllerReplicas").Return(replicasCount) + distributionFunction := GetDistributionFunction(clusterAccessor, appAccessor, "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,...) + t.Setenv(common.EnvControllerReplicas, "5") + clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() + appAccessor, _, _, _, _, _ := createTestApps() + replicasCount := 5 + db.On("GetApplicationControllerReplicas").Return(replicasCount) + filter := GetDistributionFunction(clusterAccessor, appAccessor, 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 + cluster5 := &v1alpha1.Cluster{ID: "5", Shard: &fixedShard} + clusterAccessor = getClusterAccessor([]v1alpha1.Cluster{cluster1, cluster2, cluster2, cluster4, *cluster5}) + filter = GetDistributionFunction(clusterAccessor, appAccessor, common.DefaultShardingAlgorithm, replicasCount) + assert.Equal(t, int(fixedShard), filter(cluster5)) + + fixedShard = 1 + cluster5.Shard = &fixedShard + clusterAccessor = getClusterAccessor([]v1alpha1.Cluster{cluster1, cluster2, cluster2, cluster4, *cluster5}) + filter = GetDistributionFunction(clusterAccessor, appAccessor, 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,...) + t.Setenv(common.EnvControllerReplicas, "4") + clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() + appAccessor, _, _, _, _, _ := createTestApps() + replicasCount := 4 + db.On("GetApplicationControllerReplicas").Return(replicasCount) + + filter := GetDistributionFunction(clusterAccessor, appAccessor, 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 = 1 + cluster5 := v1alpha1.Cluster{Name: "cluster5", ID: "5", Shard: &fixedShard} + clusters := []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5} + clusterAccessor = getClusterAccessor(clusters) + filter = GetDistributionFunction(clusterAccessor, appAccessor, common.RoundRobinShardingAlgorithm, replicasCount) + assert.Equal(t, int(fixedShard), filter(&cluster5)) + + fixedShard = 1 + cluster5 = v1alpha1.Cluster{Name: "cluster5", ID: "5", Shard: &fixedShard} + clusters = []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5} + clusterAccessor = getClusterAccessor(clusters) + filter = GetDistributionFunction(clusterAccessor, appAccessor, common.RoundRobinShardingAlgorithm, replicasCount) + assert.Equal(t, int(fixedShard), filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard})) +} + +func TestGetShardByIndexModuloReplicasCountDistributionFunction2(t *testing.T) { + clusters, db, cluster1, cluster2, cluster3, cluster4, cluster5 := createTestClusters() + + t.Run("replicas set to 1", func(t *testing.T) { + 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)) + assert.Equal(t, 0, distributionFunction(&cluster3)) + assert.Equal(t, 0, distributionFunction(&cluster4)) + assert.Equal(t, 0, distributionFunction(&cluster5)) + }) + + t.Run("replicas set to 2", func(t *testing.T) { + 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)) + assert.Equal(t, 0, distributionFunction(&cluster3)) + assert.Equal(t, 1, distributionFunction(&cluster4)) + assert.Equal(t, 0, distributionFunction(&cluster5)) + }) + + t.Run("replicas set to 3", func(t *testing.T) { + 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)) + assert.Equal(t, 2, distributionFunction(&cluster3)) + assert.Equal(t, 0, distributionFunction(&cluster4)) + assert.Equal(t, 1, distributionFunction(&cluster5)) + }) +} + +func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterNumberIsHigh(t *testing.T) { + // Unit test written to evaluate the cost of calling db.ListCluster on every call of distributionFunction + // Doing that allows to accept added and removed clusters on the fly. + // 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 + clusterPointers := []*v1alpha1.Cluster{} + for i := 0; i < 2048; i++ { + cluster := createCluster(fmt.Sprintf("cluster-%d", i), fmt.Sprintf("%d", i)) + clusterPointers = append(clusterPointers, &cluster) + } + 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)) + } +} + +func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterIsAddedAndRemoved(t *testing.T) { + db := dbmocks.ArgoDB{} + cluster1 := createCluster("cluster1", "1") + cluster2 := createCluster("cluster2", "2") + cluster3 := createCluster("cluster3", "3") + cluster4 := createCluster("cluster4", "4") + 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 + 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)) + assert.Equal(t, 0, distributionFunction(&cluster3)) + assert.Equal(t, 1, distributionFunction(&cluster4)) + assert.Equal(t, 0, distributionFunction(&cluster5)) + assert.Equal(t, -1, distributionFunction(&cluster6)) // as cluster6 is not in the DB, this one should not have a shard assigned + + // 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) { + 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 + expectedShardForCluster2 := 1 + shardForCluster1 := distributionFunction(&cluster1) + shardForCluster2 := distributionFunction(&cluster2) + + if shardForCluster1 != expectedShardForCluster1 { + t.Errorf("Expected shard for cluster1 to be %d but got %d", expectedShardForCluster1, shardForCluster1) + } + if shardForCluster2 != expectedShardForCluster2 { + t.Errorf("Expected shard for cluster2 to be %d but got %d", expectedShardForCluster2, shardForCluster2) + } +} + +func TestInferShard(t *testing.T) { + // Override the os.Hostname function to return a specific hostname for testing + defer func() { osHostnameFunction = os.Hostname }() + + expectedShard := 3 + osHostnameFunction = func() (string, error) { return "example-shard-3", nil } + actualShard, _ := InferShard() + assert.Equal(t, expectedShard, actualShard) + + osHostnameError := errors.New("cannot resolve hostname") + osHostnameFunction = func() (string, error) { return "exampleshard", osHostnameError } + _, err := InferShard() + assert.NotNil(t, err) + assert.Equal(t, err, osHostnameError) + + osHostnameFunction = func() (string, error) { return "exampleshard", nil } + _, err = InferShard() + assert.Nil(t, err) + + osHostnameFunction = func() (string, error) { return "example-shard", nil } + _, err = InferShard() + assert.Nil(t, err) +} + +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") + cluster3 := createCluster("cluster3", "3") + 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 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 { + cluster := v1alpha1.Cluster{ + Name: name, + ID: id, + Server: "https://kubernetes.default.svc?" + id, + } + return cluster +} + +func Test_getDefaultShardMappingData(t *testing.T) { + expectedData := []shardApplicationControllerMapping{ + { + ShardNumber: 0, + ControllerName: "", + }, { + ShardNumber: 1, + ControllerName: "", + }, + } + + shardMappingData := getDefaultShardMappingData(2) + assert.Equal(t, expectedData, shardMappingData) +} + +func Test_generateDefaultShardMappingCM_NoPredefinedShard(t *testing.T) { + replicas := 2 + expectedTime := metav1.Now() + defer func() { osHostnameFunction = os.Hostname }() + defer func() { heartbeatCurrentTime = metav1.Now }() + + expectedMapping := []shardApplicationControllerMapping{ + { + ShardNumber: 0, + ControllerName: "test-example", + HeartbeatTime: expectedTime, + }, { + ShardNumber: 1, + }, + } + + expectedMappingCM, err := json.Marshal(expectedMapping) + assert.NoError(t, err) + + expectedShadingCM := &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ArgoCDAppControllerShardConfigMapName, + Namespace: "test", + }, + Data: map[string]string{ + "shardControllerMapping": string(expectedMappingCM), + }, + } + heartbeatCurrentTime = func() metav1.Time { return expectedTime } + osHostnameFunction = func() (string, error) { return "test-example", nil } + shardingCM, err := generateDefaultShardMappingCM("test", "test-example", replicas, -1) + assert.NoError(t, err) + assert.Equal(t, expectedShadingCM, shardingCM) + +} + +func Test_generateDefaultShardMappingCM_PredefinedShard(t *testing.T) { + replicas := 2 + expectedTime := metav1.Now() + defer func() { osHostnameFunction = os.Hostname }() + defer func() { heartbeatCurrentTime = metav1.Now }() + + expectedMapping := []shardApplicationControllerMapping{ + { + ShardNumber: 0, + }, { + ShardNumber: 1, + ControllerName: "test-example", + HeartbeatTime: expectedTime, + }, + } + + expectedMappingCM, err := json.Marshal(expectedMapping) + assert.NoError(t, err) + + expectedShadingCM := &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ArgoCDAppControllerShardConfigMapName, + Namespace: "test", + }, + Data: map[string]string{ + "shardControllerMapping": string(expectedMappingCM), + }, + } + heartbeatCurrentTime = func() metav1.Time { return expectedTime } + osHostnameFunction = func() (string, error) { return "test-example", nil } + shardingCM, err := generateDefaultShardMappingCM("test", "test-example", replicas, 1) + assert.NoError(t, err) + assert.Equal(t, expectedShadingCM, shardingCM) + +} + +func Test_getOrUpdateShardNumberForController(t *testing.T) { + expectedTime := metav1.Now() + + testCases := []struct { + name string + shardApplicationControllerMapping []shardApplicationControllerMapping + hostname string + replicas int + shard int + expectedShard int + expectedShardMappingData []shardApplicationControllerMapping + }{ + { + name: "length of shard mapping less than number of replicas - Existing controller", + shardApplicationControllerMapping: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: metav1.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), + }, + }, + hostname: "test-example", + replicas: 2, + shard: -1, + expectedShard: 0, + expectedShardMappingData: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, { + ControllerName: "", + ShardNumber: 1, + HeartbeatTime: metav1.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), + }, + }, + }, + { + name: "length of shard mapping less than number of replicas - New controller", + shardApplicationControllerMapping: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, + }, + hostname: "test-example-1", + replicas: 2, + shard: -1, + expectedShard: 1, + expectedShardMappingData: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, { + ControllerName: "test-example-1", + ShardNumber: 1, + HeartbeatTime: expectedTime, + }, + }, + }, + { + name: "length of shard mapping more than number of replicas", + shardApplicationControllerMapping: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, { + ControllerName: "test-example-1", + ShardNumber: 1, + HeartbeatTime: expectedTime, + }, + }, + hostname: "test-example", + replicas: 1, + shard: -1, + expectedShard: 0, + expectedShardMappingData: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, + }, + }, + { + name: "shard number is pre-specified and length of shard mapping less than number of replicas - Existing controller", + shardApplicationControllerMapping: []shardApplicationControllerMapping{ + { + ControllerName: "test-example-1", + ShardNumber: 1, + HeartbeatTime: metav1.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), + }, { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, + }, + hostname: "test-example-1", + replicas: 2, + shard: 1, + expectedShard: 1, + expectedShardMappingData: []shardApplicationControllerMapping{ + { + ControllerName: "test-example-1", + ShardNumber: 1, + HeartbeatTime: expectedTime, + }, { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, + }, + }, + { + name: "shard number is pre-specified and length of shard mapping less than number of replicas - New controller", + shardApplicationControllerMapping: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, + }, + hostname: "test-example-1", + replicas: 2, + shard: 1, + expectedShard: 1, + expectedShardMappingData: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, { + ControllerName: "test-example-1", + ShardNumber: 1, + HeartbeatTime: expectedTime, + }, + }, + }, + { + name: "shard number is pre-specified and length of shard mapping more than number of replicas", + shardApplicationControllerMapping: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, { + ControllerName: "test-example-1", + ShardNumber: 1, + HeartbeatTime: expectedTime, + }, { + ControllerName: "test-example-2", + ShardNumber: 2, + HeartbeatTime: expectedTime, + }, + }, + hostname: "test-example", + replicas: 2, + shard: 1, + expectedShard: 1, + expectedShardMappingData: []shardApplicationControllerMapping{ + { + ControllerName: "", + ShardNumber: 0, + HeartbeatTime: metav1.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), + }, { + ControllerName: "test-example", + ShardNumber: 1, + HeartbeatTime: expectedTime, + }, + }, + }, + { + name: "updating heartbeat", + shardApplicationControllerMapping: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, { + ControllerName: "test-example-1", + ShardNumber: 1, + HeartbeatTime: metav1.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), + }, + }, + hostname: "test-example-1", + replicas: 2, + shard: -1, + expectedShard: 1, + expectedShardMappingData: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, { + ControllerName: "test-example-1", + ShardNumber: 1, + HeartbeatTime: expectedTime, + }, + }, + }, + { + name: "updating heartbeat - shard pre-defined", + shardApplicationControllerMapping: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, { + ControllerName: "test-example-1", + ShardNumber: 1, + HeartbeatTime: metav1.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), + }, + }, + hostname: "test-example-1", + replicas: 2, + shard: 1, + expectedShard: 1, + expectedShardMappingData: []shardApplicationControllerMapping{ + { + ControllerName: "test-example", + ShardNumber: 0, + HeartbeatTime: expectedTime, + }, { + ControllerName: "test-example-1", + ShardNumber: 1, + HeartbeatTime: expectedTime, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + defer func() { osHostnameFunction = os.Hostname }() + heartbeatCurrentTime = func() metav1.Time { return expectedTime } + shard, shardMappingData := getOrUpdateShardNumberForController(tc.shardApplicationControllerMapping, tc.hostname, tc.replicas, tc.shard) + assert.Equal(t, tc.expectedShard, shard) + assert.Equal(t, tc.expectedShardMappingData, shardMappingData) + }) + } +} + +func TestGetClusterSharding(t *testing.T) { + IntPtr := func(i int32) *int32 { + return &i + } + + deployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.DefaultApplicationControllerName, + Namespace: "argocd", + }, + Spec: appsv1.DeploymentSpec{ + Replicas: IntPtr(1), + }, + } + + deploymentMultiReplicas := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-application-controller-multi-replicas", + Namespace: "argocd", + }, + Spec: appsv1.DeploymentSpec{ + Replicas: IntPtr(3), + }, + } + + objects := append([]runtime.Object{}, deployment, deploymentMultiReplicas) + kubeclientset := kubefake.NewSimpleClientset(objects...) + + settingsMgr := settings.NewSettingsManager(context.TODO(), kubeclientset, "argocd", settings.WithRepoOrClusterChangedHandler(func() { + })) + + testCases := []struct { + name string + useDynamicSharding bool + envsSetter func(t *testing.T) + cleanup func() + expectedShard int + expectedReplicas int + expectedErr error + }{ + { + name: "Default sharding with statefulset", + envsSetter: func(t *testing.T) { + t.Setenv(common.EnvControllerReplicas, "1") + }, + cleanup: func() {}, + useDynamicSharding: false, + expectedShard: 0, + expectedReplicas: 1, + expectedErr: nil, + }, + { + name: "Default sharding with deployment", + envsSetter: func(t *testing.T) { + t.Setenv(common.EnvAppControllerName, common.DefaultApplicationControllerName) + }, + cleanup: func() {}, + useDynamicSharding: true, + expectedShard: 0, + expectedReplicas: 1, + expectedErr: nil, + }, + { + name: "Default sharding with deployment and multiple replicas", + envsSetter: func(t *testing.T) { + t.Setenv(common.EnvAppControllerName, "argocd-application-controller-multi-replicas") + }, + cleanup: func() {}, + useDynamicSharding: true, + expectedShard: 0, + expectedReplicas: 3, + expectedErr: nil, + }, + { + name: "Statefulset multiple replicas", + envsSetter: func(t *testing.T) { + t.Setenv(common.EnvControllerReplicas, "3") + osHostnameFunction = func() (string, error) { return "example-shard-3", nil } + }, + cleanup: func() { + osHostnameFunction = os.Hostname + }, + useDynamicSharding: false, + expectedShard: 3, + expectedReplicas: 3, + expectedErr: nil, + }, + { + name: "Explicit shard with statefulset and 1 replica", + envsSetter: func(t *testing.T) { + t.Setenv(common.EnvControllerReplicas, "1") + t.Setenv(common.EnvControllerShard, "3") + }, + cleanup: func() {}, + useDynamicSharding: false, + expectedShard: 0, + expectedReplicas: 1, + expectedErr: nil, + }, + { + name: "Explicit shard with statefulset and 2 replica - and to high shard", + envsSetter: func(t *testing.T) { + t.Setenv(common.EnvControllerReplicas, "2") + t.Setenv(common.EnvControllerShard, "3") + }, + cleanup: func() {}, + useDynamicSharding: false, + expectedShard: 0, + expectedReplicas: 2, + expectedErr: nil, + }, + { + name: "Explicit shard with statefulset and 2 replica", + envsSetter: func(t *testing.T) { + t.Setenv(common.EnvControllerReplicas, "2") + t.Setenv(common.EnvControllerShard, "1") + }, + cleanup: func() {}, + useDynamicSharding: false, + expectedShard: 1, + expectedReplicas: 2, + expectedErr: nil, + }, + { + name: "Explicit shard with deployment", + envsSetter: func(t *testing.T) { + t.Setenv(common.EnvControllerShard, "3") + }, + cleanup: func() {}, + useDynamicSharding: true, + expectedShard: 0, + expectedReplicas: 1, + expectedErr: nil, + }, + { + name: "Explicit shard with deployment and multiple replicas will read from configmap", + envsSetter: func(t *testing.T) { + t.Setenv(common.EnvAppControllerName, "argocd-application-controller-multi-replicas") + t.Setenv(common.EnvControllerShard, "3") + }, + cleanup: func() {}, + useDynamicSharding: true, + expectedShard: 0, + expectedReplicas: 3, + expectedErr: nil, + }, + { + name: "Dynamic sharding but missing deployment", + envsSetter: func(t *testing.T) { + t.Setenv(common.EnvAppControllerName, "missing-deployment") + }, + cleanup: func() {}, + useDynamicSharding: true, + expectedShard: 0, + expectedReplicas: 1, + expectedErr: fmt.Errorf("(dynamic cluster distribution) failed to get app controller deployment: deployments.apps \"missing-deployment\" not found"), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tc.envsSetter(t) + defer tc.cleanup() + shardingCache, err := GetClusterSharding(kubeclientset, settingsMgr, "round-robin", tc.useDynamicSharding) + + if shardingCache != nil { + clusterSharding := shardingCache.(*ClusterSharding) + assert.Equal(t, tc.expectedShard, clusterSharding.Shard) + assert.Equal(t, tc.expectedReplicas, clusterSharding.Replicas) + } + + if tc.expectedErr != nil { + if err != nil { + assert.Equal(t, tc.expectedErr.Error(), err.Error()) + } else { + t.Errorf("Expected error %v but got nil", tc.expectedErr) + } + } else { + assert.Nil(t, err) + } + }) + } +} + +func TestAppAwareCache(t *testing.T) { + _, db, cluster1, cluster2, cluster3, cluster4, cluster5 := createTestClusters() + _, app1, app2, app3, app4, app5 := createTestApps() + + clusterSharding := NewClusterSharding(db, 0, 1, "legacy") + + clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5}} + appList := &v1alpha1.ApplicationList{Items: []v1alpha1.Application{app1, app2, app3, app4, app5}} + clusterSharding.Init(clusterList, appList) + + appDistribution := clusterSharding.GetAppDistribution() + + assert.Equal(t, 2, appDistribution["cluster1"]) + assert.Equal(t, 2, appDistribution["cluster2"]) + assert.Equal(t, 1, appDistribution["cluster3"]) + + app6 := createApp("app6", "cluster4") + clusterSharding.AddApp(&app6) + + app1Update := createApp("app1", "cluster2") + clusterSharding.UpdateApp(&app1Update) + + clusterSharding.DeleteApp(&app3) + + appDistribution = clusterSharding.GetAppDistribution() + + assert.Equal(t, 1, appDistribution["cluster1"]) + assert.Equal(t, 2, appDistribution["cluster2"]) + assert.Equal(t, 1, appDistribution["cluster3"]) + assert.Equal(t, 1, appDistribution["cluster4"]) +} + +func createTestApps() (appAccessor, v1alpha1.Application, v1alpha1.Application, v1alpha1.Application, v1alpha1.Application, v1alpha1.Application) { + app1 := createApp("app1", "cluster1") + app2 := createApp("app2", "cluster1") + app3 := createApp("app3", "cluster2") + app4 := createApp("app4", "cluster2") + app5 := createApp("app5", "cluster3") + + apps := []v1alpha1.Application{app1, app2, app3, app4, app5} + + return getAppAccessor(apps), app1, app2, app3, app4, app5 +} + +func getAppAccessor(apps []v1alpha1.Application) appAccessor { + // Convert the array to a slice of pointers + appPointers := getAppPointers(apps) + appAccessor := func() []*v1alpha1.Application { return appPointers } + return appAccessor +} + +func getAppPointers(apps []v1alpha1.Application) []*v1alpha1.Application { + var appPointers []*v1alpha1.Application + for i := range apps { + appPointers = append(appPointers, &apps[i]) + } + return appPointers +} + +func createApp(name string, server string) v1alpha1.Application { + var testApp = ` +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: ` + name + ` +spec: + destination: + server: ` + server + ` +` + + var app v1alpha1.Application + err := yaml.Unmarshal([]byte(testApp), &app) + if err != nil { + panic(err) + } + return app } diff --git a/controller/sharding/shuffle_test.go b/controller/sharding/shuffle_test.go new file mode 100644 index 0000000000000..1cca783a2afe9 --- /dev/null +++ b/controller/sharding/shuffle_test.go @@ -0,0 +1,86 @@ +package sharding + +import ( + "fmt" + "math" + "strconv" + "testing" + + "github.com/argoproj/argo-cd/v2/common" + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestLargeShuffle(t *testing.T) { + t.Skip() + db := dbmocks.ArgoDB{} + clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{}} + for i := 0; i < math.MaxInt/4096; i += 256 { + //fmt.Fprintf(os.Stdout, "%d", i) + cluster := createCluster(fmt.Sprintf("cluster-%d", i), fmt.Sprintf("%d", i)) + clusterList.Items = append(clusterList.Items, cluster) + } + db.On("ListClusters", mock.Anything).Return(clusterList, nil) + clusterAccessor := getClusterAccessor(clusterList.Items) + // Test with replicas set to 256 + 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)) + } + +} + +func TestShuffle(t *testing.T) { + t.Skip() + db := dbmocks.ArgoDB{} + cluster1 := createCluster("cluster1", "10") + cluster2 := createCluster("cluster2", "20") + cluster3 := createCluster("cluster3", "30") + cluster4 := createCluster("cluster4", "40") + cluster5 := createCluster("cluster5", "50") + cluster6 := createCluster("cluster6", "60") + cluster25 := createCluster("cluster6", "25") + + 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") + replicasCount := 3 + 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, 2, distributionFunction(&cluster3)) + assert.Equal(t, 0, distributionFunction(&cluster4)) + assert.Equal(t, 1, distributionFunction(&cluster5)) + assert.Equal(t, 2, distributionFunction(&cluster6)) + + // Now, we remove cluster1, it should be unassigned, and all the other should be resuffled + clusterList.Items = Remove(clusterList.Items, 0) + assert.Equal(t, -1, distributionFunction(&cluster1)) + assert.Equal(t, 0, distributionFunction(&cluster2)) + assert.Equal(t, 1, distributionFunction(&cluster3)) + assert.Equal(t, 2, distributionFunction(&cluster4)) + assert.Equal(t, 0, distributionFunction(&cluster5)) + assert.Equal(t, 1, distributionFunction(&cluster6)) + + // Now, we add a cluster with an id=25 so it will be placed right after cluster2 + clusterList.Items = append(clusterList.Items, cluster25) + assert.Equal(t, -1, distributionFunction(&cluster1)) + assert.Equal(t, 0, distributionFunction(&cluster2)) + assert.Equal(t, 1, distributionFunction(&cluster25)) + assert.Equal(t, 2, distributionFunction(&cluster3)) + assert.Equal(t, 0, distributionFunction(&cluster4)) + assert.Equal(t, 1, distributionFunction(&cluster5)) + assert.Equal(t, 2, distributionFunction(&cluster6)) + +} + +func Remove(slice []v1alpha1.Cluster, s int) []v1alpha1.Cluster { + return append(slice[:s], slice[s+1:]...) +} diff --git a/controller/state.go b/controller/state.go index b9eb784e89023..704411558669b 100644 --- a/controller/state.go +++ b/controller/state.go @@ -3,11 +3,15 @@ package controller import ( "context" "encoding/json" + "errors" "fmt" "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" @@ -27,7 +31,6 @@ import ( statecache "github.com/argoproj/argo-cd/v2/controller/cache" "github.com/argoproj/argo-cd/v2/controller/metrics" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - appv1 "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" "github.com/argoproj/argo-cd/v2/util/argo" @@ -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 *appv1.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,66 +114,64 @@ 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, map[*v1alpha1.ApplicationSource]*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 { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to list Helm repositories: %w", err) } permittedHelmRepos, err := argo.GetPermittedRepos(proj, helmRepos) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get permitted Helm repositories for project %q: %w", proj.Name, err) } ts.AddCheckpoint("repo_ms") helmRepositoryCredentials, err := m.db.GetAllHelmRepositoryCredentials(context.Background()) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get Helm credentials: %w", err) } permittedHelmCredentials, err := argo.GetPermittedReposCredentials(proj, helmRepositoryCredentials) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get permitted Helm credentials for project %q: %w", proj.Name, err) } - plugins, err := m.settingsMgr.GetConfigManagementPlugins() - if err != nil { - return nil, nil, err - } enabledSourceTypes, err := m.settingsMgr.GetEnabledSourceTypes() if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get enabled source types: %w", err) } ts.AddCheckpoint("plugins_ms") - tools := make([]*appv1.ConfigManagementPlugin, len(plugins)) - for i := range plugins { - tools[i] = &plugins[i] - } kustomizeSettings, err := m.settingsMgr.GetKustomizeSettings() if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get Kustomize settings: %w", err) } helmOptions, err := m.settingsMgr.GetHelmSettings() if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get Helm settings: %w", err) } ts.AddCheckpoint("build_options_ms") serverVersion, apiResources, err := m.liveStateCache.GetVersionsInfo(app.Spec.Destination.Server) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get cluster version for cluster %q: %w", app.Spec.Destination.Server, err) } conn, repoClient, err := m.repoClientset.NewRepoServerClient() if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to connect to repo server: %w", err) } defer io.Close(conn) - manifestInfoMap := make(map[*v1alpha1.ApplicationSource]*apiclient.ManifestResponse) + manifestInfos := make([]*apiclient.ManifestResponse, 0) targetObjs := make([]*unstructured.Unstructured, 0) // Store the map of all sources having ref field into a map for applications with sources field @@ -180,11 +187,11 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp ts.AddCheckpoint("helm_ms") repo, err := m.db.GetRepository(context.Background(), source.RepoURL) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get repo %q: %w", source.RepoURL, err) } kustomizeOptions, err := kustomizeSettings.GetOptions(source) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get Kustomize options for source %d of %d: %w", i+1, len(sources), err) } ts.AddCheckpoint("version_ms") @@ -199,7 +206,6 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp AppName: app.InstanceName(m.namespace), Namespace: app.Spec.Destination.Namespace, ApplicationSource: &source, - Plugins: tools, KustomizeOptions: kustomizeOptions, KubeVersion: serverVersion, ApiVersions: argo.APIResourcesToStrings(apiResources, true), @@ -210,25 +216,21 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp HelmOptions: helmOptions, HasMultipleSources: app.Spec.HasMultipleSources(), RefSources: refSources, + ProjectName: proj.Name, + ProjectSourceRepos: proj.Spec.SourceRepos, }) if err != nil { - return nil, nil, err - } - - // GenerateManifest can return empty ManifestResponse without error if app has multiple sources - // and if any of the source does not have path and chart field not specified. - // In that scenario, we continue to the next source - if app.Spec.HasMultipleSources() && len(manifestInfo.Manifests) == 0 { - continue + return nil, nil, fmt.Errorf("failed to generate manifest for source %d of %d: %w", i+1, len(sources), err) } targetObj, err := unmarshalManifests(manifestInfo.Manifests) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to unmarshal manifests for source %d of %d: %w", i+1, len(sources), err) } targetObjs = append(targetObjs, targetObj...) - manifestInfoMap[&source] = manifestInfo + + manifestInfos = append(manifestInfos, manifestInfo) } ts.AddCheckpoint("unmarshal_ms") @@ -237,8 +239,8 @@ 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") - return targetObjs, manifestInfoMap, nil + logCtx.Info("GetRepoObjs stats") + return targetObjs, manifestInfos, nil } func unmarshalManifests(manifests []string) ([]*unstructured.Unstructured, error) { @@ -282,8 +284,8 @@ func DeduplicateTargetObjects( for key, targets := range targetByKey { if len(targets) > 1 { now := metav1.Now() - conditions = append(conditions, appv1.ApplicationCondition{ - Type: appv1.ApplicationConditionRepeatedResourceWarning, + conditions = append(conditions, v1alpha1.ApplicationCondition{ + Type: v1alpha1.ApplicationConditionRepeatedResourceWarning, Message: fmt.Sprintf("Resource %s appeared %d times among application resources.", key.String(), len(targets)), LastTransitionTime: &now, }) @@ -314,9 +316,9 @@ func (m *appStateManager) getComparisonSettings() (string, map[string]v1alpha1.R // verifyGnuPGSignature verifies the result of a GnuPG operation for a given git // revision. -func verifyGnuPGSignature(revision string, project *appv1.AppProject, manifestInfo *apiclient.ManifestResponse) []appv1.ApplicationCondition { +func verifyGnuPGSignature(revision string, project *v1alpha1.AppProject, manifestInfo *apiclient.ManifestResponse) []v1alpha1.ApplicationCondition { now := metav1.Now() - conditions := make([]appv1.ApplicationCondition, 0) + conditions := make([]v1alpha1.ApplicationCondition, 0) // We need to have some data in the verification result to parse, otherwise there was no signature if manifestInfo.VerifyResult != "" { verifyResult := gpg.ParseGitCommitVerification(manifestInfo.VerifyResult) @@ -351,10 +353,14 @@ func verifyGnuPGSignature(revision string, project *appv1.AppProject, manifestIn return conditions } +func isManagedNamespace(ns *unstructured.Unstructured, app *v1alpha1.Application) bool { + return ns != nil && ns.GetKind() == kubeutil.NamespaceKind && ns.GetName() == app.Spec.Destination.Namespace && app.Spec.SyncPolicy != nil && app.Spec.SyncPolicy.ManagedNamespaceMetadata != nil +} + // 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 *appv1.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() @@ -365,21 +371,21 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap if hasMultipleSources { return &comparisonResult{ syncStatus: &v1alpha1.SyncStatus{ - ComparedTo: appv1.ComparedTo{Destination: app.Spec.Destination, Sources: sources}, - Status: appv1.SyncStatusCodeUnknown, + ComparedTo: v1alpha1.ComparedTo{Destination: app.Spec.Destination, Sources: sources, IgnoreDifferences: app.Spec.IgnoreDifferences}, + Status: v1alpha1.SyncStatusCodeUnknown, Revisions: revisions, }, - healthStatus: &appv1.HealthStatus{Status: health.HealthStatusUnknown}, - } + healthStatus: &v1alpha1.HealthStatus{Status: health.HealthStatusUnknown}, + }, nil } else { return &comparisonResult{ syncStatus: &v1alpha1.SyncStatus{ - ComparedTo: appv1.ComparedTo{Source: sources[0], Destination: app.Spec.Destination}, - Status: appv1.SyncStatusCodeUnknown, + ComparedTo: v1alpha1.ComparedTo{Source: sources[0], Destination: app.Spec.Destination, IgnoreDifferences: app.Spec.IgnoreDifferences}, + Status: v1alpha1.SyncStatusCodeUnknown, Revision: revisions[0], }, - healthStatus: &appv1.HealthStatus{Status: health.HealthStatusUnknown}, - } + healthStatus: &v1alpha1.HealthStatus{Status: health.HealthStatusUnknown}, + }, nil } } @@ -399,7 +405,8 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap var targetObjs []*unstructured.Unstructured now := metav1.Now() - var manifestInfoMap map[*v1alpha1.ApplicationSource]*apiclient.ManifestResponse + var manifestInfos []*apiclient.ManifestResponse + targetNsExists := false if len(localManifests) == 0 { // If the length of revisions is not same as the length of sources, @@ -411,11 +418,26 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap } } - targetObjs, manifestInfoMap, 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) - conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now}) + 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 @@ -429,14 +451,13 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap targetObjs, err = unmarshalManifests(localManifests) if err != nil { targetObjs = make([]*unstructured.Unstructured, 0) - conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now}) + msg := fmt.Sprintf("Failed to load local manifests: %s", err.Error()) + conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: msg, LastTransitionTime: &now}) failedToLoadObjs = true } } // empty out manifestInfoMap - for as := range manifestInfoMap { - delete(manifestInfoMap, as) - } + manifestInfos = make([]*apiclient.ManifestResponse, 0) } ts.AddCheckpoint("git_ms") @@ -447,7 +468,8 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap } targetObjs, dedupConditions, err := DeduplicateTargetObjects(app.Spec.Destination.Namespace, targetObjs, infoProvider) if err != nil { - conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now}) + msg := fmt.Sprintf("Failed to deduplicate target state: %s", err.Error()) + conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: msg, LastTransitionTime: &now}) } conditions = append(conditions, dedupConditions...) for i := len(targetObjs) - 1; i >= 0; i-- { @@ -461,26 +483,39 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap 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") liveObjByKey, err := m.liveStateCache.GetManagedLiveObjs(app, targetObjs) if err != nil { liveObjByKey = make(map[kubeutil.ResourceKey]*unstructured.Unstructured) - conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now}) + msg := fmt.Sprintf("Failed to load live state: %s", err.Error()) + conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: msg, LastTransitionTime: &now}) failedToLoadObjs = true } - logCtx.Debugf("Retrieved lived manifests") + logCtx.Debugf("Retrieved live manifests") // filter out all resources which are not permitted in the application project for k, v := range liveObjByKey { - permitted, err := project.IsLiveResourcePermitted(v, app.Spec.Destination.Server, app.Spec.Destination.Name, func(project string) ([]*appv1.Cluster, error) { - return m.db.GetProjectClusters(context.TODO(), project) + permitted, err := project.IsLiveResourcePermitted(v, app.Spec.Destination.Server, app.Spec.Destination.Name, func(project string) ([]*v1alpha1.Cluster, error) { + clusters, err := m.db.GetProjectClusters(context.TODO(), project) + if err != nil { + return nil, fmt.Errorf("failed to get clusters for project %q: %v", project, err) + } + return clusters, nil }) if err != nil { - conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now}) + msg := fmt.Sprintf("Failed to check if live resource %q is permitted in project %q: %s", k.String(), app.Spec.Project, err.Error()) + conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: msg, LastTransitionTime: &now}) failedToLoadObjs = true continue } @@ -503,6 +538,44 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap LastTransitionTime: &now, }) } + + // For the case when a namespace is managed with `managedNamespaceMetadata` AND it has resource tracking + // enabled (e.g. someone manually adds resource tracking labels or annotations), we need to do some + // bookkeeping in order to prevent the managed namespace from being pruned. + // + // Live namespaces which are managed namespaces (i.e. application namespaces which are managed with + // CreateNamespace=true and has non-nil managedNamespaceMetadata) will (usually) not have a corresponding + // 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. + // + // 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) + + if err != nil { + conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now}) + failedToLoadObjs = true + continue + } + + // No need to care about the return value here, we just want the modified managedNs + _, err = syncNamespace(m.resourceTracking, appLabelKey, trackingMethod, app.Name, app.Spec.SyncPolicy)(managedNs, liveObj) + if err != nil { + conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now}) + failedToLoadObjs = true + } else { + targetObjs = append(targetObjs, managedNs) + } + } + } + } + hasPostDeleteHooks := false + for _, obj := range targetObjs { + if isPostDeleteHook(obj) { + hasPostDeleteHooks = true } } @@ -516,25 +589,33 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap } manifestRevisions := make([]string, 0) - for _, manifestInfo := range manifestInfoMap { + for _, manifestInfo := range manifestInfos { manifestRevisions = append(manifestRevisions, manifestInfo.Revision) } - // restore comparison using cached diff result if previous comparison was performed for the same revision - revisionChanged := len(manifestInfoMap) != len(sources) || !reflect.DeepEqual(app.Status.Sync.Revisions, manifestRevisions) - specChanged := !reflect.DeepEqual(app.Status.Sync.ComparedTo, appv1.ComparedTo{Source: app.Spec.GetSource(), Destination: app.Spec.Destination, Sources: sources}) + serverSideDiff := m.serverSideDiff || + resourceutil.HasAnnotationOption(app, common.AnnotationCompareOptions, "ServerSideDiff=true") + + // 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 + } - _, refreshRequested := app.IsRefreshRequested() - noCache = noCache || refreshRequested || app.Status.Expired(m.statusRefreshTimeout) || specChanged || revisionChanged + 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) @@ -544,6 +625,18 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap 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) @@ -557,7 +650,8 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap if err != nil { diffResults = &diff.DiffResultList{} failedToLoadObjs = true - conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now}) + msg := fmt.Sprintf("Failed to compare desired state to live state: %s", err.Error()) + conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: msg, LastTransitionTime: &now}) } ts.AddCheckpoint("diff_ms") @@ -583,7 +677,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap 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 { @@ -596,12 +690,22 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap } else { diffResult = diff.DiffResult{Modified: false, NormalizedLive: []byte("{}"), PredictedLive: []byte("{}")} } + + // For the case when a namespace is managed with `managedNamespaceMetadata` AND it has resource tracking + // enabled (e.g. someone manually adds resource tracking labels or annotations), we need to do some + // bookkeeping in order to ensure that it's not considered `OutOfSync` (since it does not exist in source + // control). + // + // This is in addition to the bookkeeping we do (see `isManagedNamespace` and its references) to prevent said + // namespace from being pruned. + isManagedNs := isManagedNamespace(targetObj, app) && liveObj == nil + if resState.Hook || ignore.Ignore(obj) || (targetObj != nil && hookutil.Skip(targetObj)) || !isSelfReferencedObj { // For resource hooks, skipped resources or objects that may have // been created by another controller with annotations copied from // the source object, don't store sync status, and do not affect // overall sync status - } else if diffResult.Modified || targetObj == nil || liveObj == nil { + } else if !isManagedNs && (diffResult.Modified || targetObj == nil || liveObj == nil) { // Set resource state to OutOfSync since one of the following is true: // * target and live resource are different // * target resource not defined and live resource is extra @@ -622,7 +726,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap } if isNamespaced && obj.GetNamespace() == "" { - conditions = append(conditions, appv1.ApplicationCondition{Type: v1alpha1.ApplicationConditionInvalidSpecError, Message: fmt.Sprintf("Namespace for %s %s is missing.", obj.GetName(), gvk.String()), LastTransitionTime: &now}) + conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionInvalidSpecError, Message: fmt.Sprintf("Namespace for %s %s is missing.", obj.GetName(), gvk.String()), LastTransitionTime: &now}) } // we can't say anything about the status if we were unable to get the target objects @@ -651,6 +755,8 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap if failedToLoadObjs { syncCode = v1alpha1.SyncStatusCodeUnknown + } else if app.HasChangedManagedNamespaceMetadata() { + syncCode = v1alpha1.SyncStatusCodeOutOfSync } var revision string @@ -660,18 +766,20 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap var syncStatus v1alpha1.SyncStatus if hasMultipleSources { syncStatus = v1alpha1.SyncStatus{ - ComparedTo: appv1.ComparedTo{ - Destination: app.Spec.Destination, - Sources: sources, + ComparedTo: v1alpha1.ComparedTo{ + Destination: app.Spec.Destination, + Sources: sources, + IgnoreDifferences: app.Spec.IgnoreDifferences, }, Status: syncCode, Revisions: manifestRevisions, } } else { syncStatus = v1alpha1.SyncStatus{ - ComparedTo: appv1.ComparedTo{ - Destination: app.Spec.Destination, - Source: app.Spec.GetSource(), + ComparedTo: v1alpha1.ComparedTo{ + Destination: app.Spec.Destination, + Source: app.Spec.GetSource(), + IgnoreDifferences: app.Spec.IgnoreDifferences, }, Status: syncCode, Revision: revision, @@ -682,13 +790,13 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap healthStatus, err := setApplicationHealth(managedResources, resourceSummaries, resourceOverrides, app, m.persistResourceHealth) if err != nil { - conditions = append(conditions, appv1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now}) + conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: fmt.Sprintf("error setting app health: %s", err.Error()), LastTransitionTime: &now}) } // Git has already performed the signature verification via its GPG interface, and the result is available // in the manifest info received from the repository server. We now need to form our opinion about the result // and stop processing if we do not agree about the outcome. - for _, manifestInfo := range manifestInfoMap { + for _, manifestInfo := range manifestInfos { if gpg.IsGPGEnabled() && verifySignature && manifestInfo != nil { conditions = append(conditions, verifyGnuPGSignature(manifestInfo.Revision, project, manifestInfo)...) } @@ -702,31 +810,86 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap reconciliationResult: reconciliation, diffConfig: diffConfig, diffResultList: diffResults, + hasPostDeleteHooks: hasPostDeleteHooks, } if hasMultipleSources { - for _, manifestInfo := range manifestInfoMap { - compRes.appSourceTypes = append(compRes.appSourceTypes, appv1.ApplicationSourceType(manifestInfo.SourceType)) + for _, manifestInfo := range manifestInfos { + compRes.appSourceTypes = append(compRes.appSourceTypes, v1alpha1.ApplicationSourceType(manifestInfo.SourceType)) } } else { - for _, manifestInfo := range manifestInfoMap { + for _, manifestInfo := range manifestInfos { compRes.appSourceType = v1alpha1.ApplicationSourceType(manifestInfo.SourceType) break } } - app.Status.SetConditions(conditions, map[appv1.ApplicationConditionType]bool{ - appv1.ApplicationConditionComparisonError: true, - appv1.ApplicationConditionSharedResourceWarning: true, - appv1.ApplicationConditionRepeatedResourceWarning: true, - appv1.ApplicationConditionExcludedResourceWarning: true, + app.Status.SetConditions(conditions, map[v1alpha1.ApplicationConditionType]bool{ + v1alpha1.ApplicationConditionComparisonError: true, + v1alpha1.ApplicationConditionSharedResourceWarning: true, + v1alpha1.ApplicationConditionRepeatedResourceWarning: true, + v1alpha1.ApplicationConditionExcludedResourceWarning: true, }) 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 @@ -739,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{ @@ -747,6 +911,7 @@ func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revi DeployStartedAt: &startedAt, ID: nextID, Source: source, + InitiatedBy: initiatedBy, }) } @@ -779,6 +944,8 @@ func NewAppStateManager( statusRefreshTimeout time.Duration, resourceTracking argo.ResourceTracking, persistResourceHealth bool, + repoErrorGracePeriod time.Duration, + serverSideDiff bool, ) AppStateManager { return &appStateManager{ liveStateCache: liveStateCache, @@ -794,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 8883464267538..d21cda62137de 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,8 @@ import ( "k8s.io/apimachinery/pkg/runtime" "github.com/argoproj/argo-cd/v2/common" + "github.com/argoproj/argo-cd/v2/controller/testdata" + "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 +43,243 @@ 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) + assert.Len(t, compRes.resources, 0) + assert.Len(t, compRes.managedResources, 0) + 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() + 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: make(map[kube.ResourceKey]*unstructured.Unstructured), + } + 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, 0) + assert.Len(t, compRes.managedResources, 0) + 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() + 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{ + ManagedNamespaceMetadata: &argoappv1.ManagedNamespaceMetadata{ + Labels: map[string]string{ + "foo": "bar", + }, + Annotations: map[string]string{ + "foo": "bar", + }, + }, + }, + } + + data := fakeData{ + manifestResponse: &apiclient.ManifestResponse{ + Manifests: []string{}, + Namespace: test.FakeDestNamespace, + Server: test.FakeClusterURL, + Revision: "abc123", + }, + managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), + } + 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.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -64,12 +301,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) @@ -95,12 +333,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)) @@ -125,12 +364,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)) @@ -156,12 +396,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)) @@ -185,13 +426,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) @@ -218,12 +460,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) @@ -233,6 +476,75 @@ func TestCompareAppStateExtraHook(t *testing.T) { assert.Equal(t, 0, len(app.Status.Conditions)) } +// TestAppRevisions tests that revisions are properly propagated for a single source app +func TestAppRevisionsSingleSource(t *testing.T) { + obj1 := NewPod() + obj1.SetNamespace(test.FakeDestNamespace) + data := fakeData{ + manifestResponse: &apiclient.ManifestResponse{ + Manifests: []string{toJSON(t, obj1)}, + Namespace: test.FakeDestNamespace, + Server: test.FakeClusterURL, + Revision: "abc123", + }, + managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), + } + ctrl := newFakeController(&data, nil) + + app := newFakeApp() + revisions := make([]string, 0) + revisions = append(revisions, "") + 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) + assert.Len(t, compRes.syncStatus.Revisions, 0) +} + +// TestAppRevisions tests that revisions are properly propagated for a multi source app +func TestAppRevisionsMultiSource(t *testing.T) { + obj1 := NewPod() + obj1.SetNamespace(test.FakeDestNamespace) + data := fakeData{ + manifestResponses: []*apiclient.ManifestResponse{ + { + Manifests: []string{toJSON(t, obj1)}, + Namespace: test.FakeDestNamespace, + Server: test.FakeClusterURL, + Revision: "abc123", + }, + { + Manifests: []string{toJSON(t, obj1)}, + Namespace: test.FakeDestNamespace, + Server: test.FakeClusterURL, + Revision: "def456", + }, + { + Manifests: []string{}, + Namespace: test.FakeDestNamespace, + Server: test.FakeClusterURL, + Revision: "ghi789", + }, + }, + managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), + } + ctrl := newFakeController(&data, nil) + + app := newFakeMultiSourceApp() + revisions := make([]string, 0) + revisions = append(revisions, "") + 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) + assert.Len(t, compRes.syncStatus.Revisions, 3) + assert.Equal(t, "abc123", compRes.syncStatus.Revisions[0]) + assert.Equal(t, "def456", compRes.syncStatus.Revisions[1]) + assert.Equal(t, "ghi789", compRes.syncStatus.Revisions[2]) +} + func toJSON(t *testing.T, obj *unstructured.Unstructured) string { data, err := json.Marshal(obj) assert.NoError(t, err) @@ -265,12 +577,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)) @@ -280,6 +593,48 @@ func TestCompareAppStateDuplicatedNamespacedResources(t *testing.T) { assert.Equal(t, 4, len(compRes.resources)) } +func TestCompareAppStateManagedNamespaceMetadataWithLiveNsDoesNotGetPruned(t *testing.T) { + app := newFakeApp() + app.Spec.SyncPolicy = &argoappv1.SyncPolicy{ + ManagedNamespaceMetadata: &argoappv1.ManagedNamespaceMetadata{ + Labels: nil, + Annotations: nil, + }, + } + + ns := NewNamespace() + ns.SetName(test.FakeDestNamespace) + ns.SetNamespace(test.FakeDestNamespace) + ns.SetAnnotations(map[string]string{"argocd.argoproj.io/sync-options": "ServerSideApply=true"}) + + 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) + 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)) + assert.NotNil(t, compRes) + assert.NotNil(t, compRes.syncStatus) + // Ensure that ns does not get pruned + assert.NotNil(t, compRes.reconciliationResult.Target[0]) + assert.Equal(t, compRes.reconciliationResult.Target[0].GetName(), ns.GetName()) + assert.Equal(t, compRes.reconciliationResult.Target[0].GetAnnotations(), ns.GetAnnotations()) + assert.Equal(t, compRes.reconciliationResult.Target[0].GetLabels(), ns.GetLabels()) + assert.Len(t, compRes.resources, 1) + assert.Len(t, compRes.managedResources, 1) +} + var defaultProj = argoappv1.AppProject{ ObjectMeta: metav1.ObjectMeta{ Name: "default", @@ -319,13 +674,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) } @@ -355,13 +711,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) } @@ -381,7 +738,7 @@ func TestSetManagedResourcesWithOrphanedResources(t *testing.T) { AppName: "", }, }, - }) + }, nil) tree, err := ctrl.setAppManagedResources(app, &comparisonResult{managedResources: make([]managedResource, 0)}) @@ -410,7 +767,7 @@ func TestSetManagedResourcesWithResourcesOfAnotherApp(t *testing.T) { AppName: "app2", }, }, - }) + }, nil) tree, err := ctrl.setAppManagedResources(app1, &comparisonResult{managedResources: make([]managedResource, 0)}) @@ -429,13 +786,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) @@ -462,7 +820,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)}) @@ -475,14 +833,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() @@ -518,7 +876,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) } @@ -555,9 +913,8 @@ var signedProj = argoappv1.AppProject{ } func TestSignedResponseNoSignatureRequired(t *testing.T) { - oldval := os.Getenv("ARGOCD_GPG_ENABLED") - os.Setenv("ARGOCD_GPG_ENABLED", "true") - defer os.Setenv("ARGOCD_GPG_ENABLED", oldval) + t.Setenv("ARGOCD_GPG_ENABLED", "true") + // We have a good signature response, but project does not require signed commits { app := newFakeApp() @@ -571,12 +928,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) @@ -597,12 +955,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) @@ -613,9 +972,7 @@ func TestSignedResponseNoSignatureRequired(t *testing.T) { } func TestSignedResponseSignatureRequired(t *testing.T) { - oldval := os.Getenv("ARGOCD_GPG_ENABLED") - os.Setenv("ARGOCD_GPG_ENABLED", "true") - defer os.Setenv("ARGOCD_GPG_ENABLED", oldval) + t.Setenv("ARGOCD_GPG_ENABLED", "true") // We have a good signature response, valid key, and signing is required - sync! { @@ -630,12 +987,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) @@ -656,12 +1014,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) @@ -682,12 +1041,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) @@ -708,12 +1068,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) @@ -735,14 +1096,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) @@ -766,12 +1128,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) @@ -781,7 +1144,7 @@ func TestSignedResponseSignatureRequired(t *testing.T) { assert.Contains(t, app.Status.Conditions[0].Message, "Cannot use local manifests") } - os.Setenv("ARGOCD_GPG_ENABLED", "false") + t.Setenv("ARGOCD_GPG_ENABLED", "false") // We have a bad signature response and signing would be required, but GPG subsystem is disabled - sync { app := newFakeApp() @@ -795,12 +1158,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) @@ -824,12 +1188,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) @@ -837,7 +1202,6 @@ func TestSignedResponseSignatureRequired(t *testing.T) { assert.Len(t, compRes.managedResources, 0) assert.Len(t, app.Status.Conditions, 0) } - } func TestComparisonResult_GetHealthStatus(t *testing.T) { @@ -965,7 +1329,7 @@ func TestIsLiveResourceManaged(t *testing.T) { kube.GetResourceKey(unmanagedObjWrongGroup): unmanagedObjWrongGroup, kube.GetResourceKey(unmanagedObjWrongNamespace): unmanagedObjWrongNamespace, }, - }) + }, nil) manager := ctrl.appStateManager.(*appStateManager) appName := "guestbook" @@ -1034,3 +1398,283 @@ 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 with sync policy", + noCache: false, + manifestInfos: manifestInfos("rev1"), + sources: sources(), + app: test.YamlToApplication(testdata.DiffCacheYaml), + manifestRevisions: []string{"rev1"}, + statusRefreshTimeout: time.Hour * 24, + expectedUseCache: true, + serverSideDiff: true, + }, + { + 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 65e86851ee364..401d08bc56ea4 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 } @@ -139,6 +161,12 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha state.Phase = common.OperationError state.Message = fmt.Sprintf("Failed to load application project: %v", err) return + } else if syncWindowPreventsSync(app, proj) { + // If the operation is currently running, simply let the user know the sync is blocked by a current sync window + if state.Phase == common.OperationRunning { + state.Message = "Sync operation blocked by sync window" + } + return } if app.Spec.HasMultipleSources() { @@ -152,7 +180,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 +310,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) }), @@ -322,7 +357,29 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha var resState []common.ResourceSyncResult state.Phase, state.Message, resState = syncCtx.GetState() state.SyncResult.Resources = nil + + if app.Spec.SyncPolicy != nil { + state.SyncResult.ManagedNamespaceMetadata = app.Spec.SyncPolicy.ManagedNamespaceMetadata + } + + var apiVersion []kube.APIResourceInfo for _, res := range resState { + augmentedMsg, err := argo.AugmentSyncMsg(res, func() ([]kube.APIResourceInfo, error) { + if apiVersion == nil { + _, apiVersion, err = m.liveStateCache.GetVersionsInfo(app.Spec.Destination.Server) + if err != nil { + return nil, fmt.Errorf("failed to get version info from the target cluster %q", app.Spec.Destination.Server) + } + } + return apiVersion, nil + }) + + if err != nil { + log.Errorf("using the original message since: %v", err) + } else { + res.Message = augmentedMsg + } + state.SyncResult.Resources = append(state.SyncResult.Resources, &v1alpha1.ResourceResult{ HookType: res.HookType, Group: res.ResourceKey.Group, @@ -340,7 +397,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) @@ -522,3 +579,12 @@ func delayBetweenSyncWaves(phase common.SyncPhase, wave int, finalWave bool) err } return nil } + +func syncWindowPreventsSync(app *v1alpha1.Application, proj *v1alpha1.AppProject) bool { + window := proj.Spec.SyncWindows.Matches(app) + isManual := false + if app.Status.OperationState != nil { + isManual = !app.Status.OperationState.Operation.InitiatedBy.Automated + } + return !window.CanSync(isManual) +} diff --git a/controller/sync_test.go b/controller/sync_test.go index 13406ddc0cb0e..f9bd81c1c138a 100644 --- a/controller/sync_test.go +++ b/controller/sync_test.go @@ -2,7 +2,6 @@ package controller import ( "context" - "os" "testing" "github.com/argoproj/gitops-engine/pkg/sync" @@ -42,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{ @@ -59,6 +58,46 @@ func TestPersistRevisionHistory(t *testing.T) { assert.Equal(t, "abc123", updatedApp.Status.History[0].Revision) } +func TestPersistManagedNamespaceMetadataState(t *testing.T) { + app := newFakeApp() + app.Status.OperationState = nil + app.Status.History = nil + app.Spec.SyncPolicy.ManagedNamespaceMetadata = &v1alpha1.ManagedNamespaceMetadata{ + Labels: map[string]string{ + "foo": "bar", + }, + Annotations: map[string]string{ + "foo": "bar", + }, + } + + defaultProject := &v1alpha1.AppProject{ + ObjectMeta: v1.ObjectMeta{ + Namespace: test.FakeArgoCDNamespace, + Name: "default", + }, + } + data := fakeData{ + apps: []runtime.Object{app, defaultProject}, + manifestResponse: &apiclient.ManifestResponse{ + Manifests: []string{}, + Namespace: test.FakeDestNamespace, + Server: test.FakeClusterURL, + Revision: "abc123", + }, + managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), + } + ctrl := newFakeController(&data, nil) + + // Sync with source unspecified + opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{ + Sync: &v1alpha1.SyncOperation{}, + }} + ctrl.appStateManager.SyncAppState(app, opState) + // Ensure we record spec.syncPolicy.managedNamespaceMetadata into sync result + assert.Equal(t, app.Spec.SyncPolicy.ManagedNamespaceMetadata, opState.SyncResult.ManagedNamespaceMetadata) +} + func TestPersistRevisionHistoryRollback(t *testing.T) { app := newFakeApp() app.Status.OperationState = nil @@ -79,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{ @@ -133,14 +172,13 @@ 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{ Sync: &v1alpha1.SyncOperation{}, }} - os.Setenv("ARGOCD_GPG_ENABLED", "true") - defer os.Setenv("ARGOCD_GPG_ENABLED", "false") + t.Setenv("ARGOCD_GPG_ENABLED", "true") ctrl.appStateManager.SyncAppState(app, opState) conditions := app.Status.GetConditions(map[v1alpha1.ApplicationConditionType]bool{v1alpha1.ApplicationConditionComparisonError: true}) @@ -179,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, @@ -216,6 +254,75 @@ func TestAppStateManager_SyncAppState(t *testing.T) { }) } +func TestSyncWindowDeniesSync(t *testing.T) { + type fixture struct { + project *v1alpha1.AppProject + application *v1alpha1.Application + controller *ApplicationController + } + + setup := func() *fixture { + app := newFakeApp() + app.Status.OperationState = nil + app.Status.History = nil + + project := &v1alpha1.AppProject{ + ObjectMeta: v1.ObjectMeta{ + Namespace: test.FakeArgoCDNamespace, + Name: "default", + }, + Spec: v1alpha1.AppProjectSpec{ + SyncWindows: v1alpha1.SyncWindows{{ + Kind: "deny", + Schedule: "0 0 * * *", + Duration: "24h", + Clusters: []string{"*"}, + Namespaces: []string{"*"}, + Applications: []string{"*"}, + }}, + }, + } + data := fakeData{ + apps: []runtime.Object{app, project}, + manifestResponse: &apiclient.ManifestResponse{ + Manifests: []string{}, + Namespace: test.FakeDestNamespace, + Server: test.FakeClusterURL, + Revision: "abc123", + }, + managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), + } + ctrl := newFakeController(&data, nil) + + return &fixture{ + project: project, + application: app, + controller: ctrl, + } + } + + t.Run("will keep the sync progressing if a sync window prevents the sync", func(t *testing.T) { + // given a project with an active deny sync window and an operation in progress + t.Parallel() + f := setup() + opMessage := "Sync operation blocked by sync window" + + opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{ + Sync: &v1alpha1.SyncOperation{ + Source: &v1alpha1.ApplicationSource{}, + }}, + Phase: common.OperationRunning, + } + // when + f.controller.appStateManager.SyncAppState(f.application, opState) + + //then + assert.Equal(t, common.OperationRunning, opState.Phase) + assert.Contains(t, opState.Message, opMessage) + }) + +} + func TestNormalizeTargetResources(t *testing.T) { type fixture struct { comparisonResult *comparisonResult diff --git a/controller/testdata/data.go b/controller/testdata/data.go index a53c6a8a88b35..028a7caaeac6b 100644 --- a/controller/testdata/data.go +++ b/controller/testdata/data.go @@ -11,4 +11,7 @@ var ( //go:embed target-deployment-new-entries.yaml TargetDeploymentNewEntries string + + //go:embed diff-cache.yaml + DiffCacheYaml string ) diff --git a/controller/testdata/diff-cache.yaml b/controller/testdata/diff-cache.yaml new file mode 100644 index 0000000000000..41a1e8a4bbeb1 --- /dev/null +++ b/controller/testdata/diff-cache.yaml @@ -0,0 +1,498 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd-image-updater.argoproj.io/allow-tags: any + argocd-image-updater.argoproj.io/ignore-tags: "" + argocd-image-updater.argoproj.io/image-list-disabled-hack: "" + argocd-image-updater.argoproj.io/update-strategy: semver + argocd-image-updater.argoproj.io/write-back-method: git + argocd-image-updater.argoproj.io/write-back-target: kustomization + argocd-notif-onDeployed.slack-disabled: "" + argocd-notif-onHealthDegraded.slack-disabled: "" + argocd-notif-onSyncFailed.slack-disabled: "" + argocd-notif-onSyncRunning.slack-disabled: "" + argocd-notif-onSyncStatusUnknown.slack-disabled: "" + argocd-notif-onSyncSucceeded.slack-disabled: "" + argocd.argoproj.io/compare-options: ServerSideDiff=true + argocd.argoproj.io/manifest-generate-paths: .;/chart + creationTimestamp: "2024-03-04T21:30:33Z" + finalizers: + - resources-finalizer.argocd.argoproj.io + generation: 263 + labels: + cloud_provider: gcp + cluster_name: gke-alpha-01-europe-west1 + foo: bar + preview: "true" + project: sre + service_class: alpha + stack: gke-v2 + name: velero-test + namespace: argo-cd + ownerReferences: + - apiVersion: argoproj.io/v1alpha1 + blockOwnerDeletion: true + controller: true + kind: ApplicationSet + name: velero + uid: 86cdfba4-8697-47b3-8489-71fab7f4a805 + resourceVersion: "722811357" + uid: 94978696-4fd4-40b3-a1de-38d9df9e9316 +spec: + destination: + name: gke-alpha-01-europe-west1 + namespace: test-lla + project: sre + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + syncPolicy: + retry: + backoff: + duration: 5s + factor: 2 + maxDuration: 3m + limit: 10 + syncOptions: + - CreateNamespace=true + - ApplyOutOfSyncOnly=true + - RespectIgnoreDifferences=false + - ServerSideApply=true + - Validate=true +status: + controllerNamespace: argo-cd + health: + status: Healthy + history: + - deployStartedAt: "2024-03-04T22:00:05Z" + deployedAt: "2024-03-04T22:00:06Z" + id: 14 + revision: ea8759964626a583667a2bfd08f334ec2070040a + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + - deployStartedAt: "2024-03-04T22:08:29Z" + deployedAt: "2024-03-04T22:08:30Z" + id: 15 + revision: ea8759964626a583667a2bfd08f334ec2070040a + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + - deployStartedAt: "2024-03-04T22:09:16Z" + deployedAt: "2024-03-04T22:09:16Z" + id: 16 + revision: ea8759964626a583667a2bfd08f334ec2070040a + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + - deployStartedAt: "2024-03-04T22:11:41Z" + deployedAt: "2024-03-04T22:11:41Z" + id: 17 + revision: ea8759964626a583667a2bfd08f334ec2070040a + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + - deployStartedAt: "2024-03-04T22:50:55Z" + deployedAt: "2024-03-04T22:50:55Z" + id: 18 + revision: ea8759964626a583667a2bfd08f334ec2070040a + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + - deployStartedAt: "2024-03-04T22:52:56Z" + deployedAt: "2024-03-04T22:52:56Z" + id: 19 + revision: ea8759964626a583667a2bfd08f334ec2070040a + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + - deployStartedAt: "2024-03-04T22:56:15Z" + deployedAt: "2024-03-04T22:56:15Z" + id: 20 + revision: ea8759964626a583667a2bfd08f334ec2070040a + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + - deployStartedAt: "2024-03-05T07:31:56Z" + deployedAt: "2024-03-05T07:31:57Z" + id: 21 + revision: ea8759964626a583667a2bfd08f334ec2070040a + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + - deployStartedAt: "2024-03-05T07:32:44Z" + deployedAt: "2024-03-05T07:32:44Z" + id: 22 + revision: ea8759964626a583667a2bfd08f334ec2070040a + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + - deployStartedAt: "2024-03-05T07:33:03Z" + deployedAt: "2024-03-05T07:33:04Z" + id: 23 + revision: ea8759964626a583667a2bfd08f334ec2070040a + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + operationState: + finishedAt: "2024-03-05T07:33:04Z" + message: successfully synced (all tasks run) + operation: + initiatedBy: + username: laurent.lavaud@mirakl.com + retry: + backoff: + duration: 5s + factor: 2 + maxDuration: 3m + limit: 10 + sync: + revision: ea8759964626a583667a2bfd08f334ec2070040a + syncOptions: + - ServerSideApply=true + syncStrategy: + hook: {} + phase: Succeeded + startedAt: "2024-03-05T07:33:03Z" + syncResult: + resources: + - group: "" + hookPhase: Running + kind: Service + message: service/test-lla serverside-applied + name: test-lla + namespace: test-lla + status: Synced + syncPhase: Sync + version: v1 + - group: apps + hookPhase: Running + kind: Deployment + message: deployment.apps/test-lla serverside-applied + name: test-lla + namespace: test-lla + status: Synced + syncPhase: Sync + version: v1 + revision: ea8759964626a583667a2bfd08f334ec2070040a + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + reconciledAt: "2024-03-05T07:33:04Z" + resources: + - health: + status: Healthy + kind: Service + name: test-lla + namespace: test-lla + status: Synced + version: v1 + - group: apps + health: + status: Healthy + kind: Deployment + name: test-lla + namespace: test-lla + status: Synced + version: v1 + sourceType: Plugin + summary: + images: + - nginx:latest + sync: + comparedTo: + destination: + name: gke-alpha-01-europe-west1 + namespace: test-lla + source: + path: instances/test + plugin: + env: + - name: RELEASE_NAME + value: test-lla + - name: CHART_REPOSITORY + value: oci://europe-west1-docker.pkg.dev/platform-89be/charts + - name: CHART_NAME + value: velero + - name: PREVIEW + value: "false" + - name: HELM_VALUES + value: | + global: + app: + cluster_name: gke-alpha-01-europe-west1 + service_class: alpha + cloud_provider: gcp + cluster_stack: gke-v2 + - name: HELM_ARGS + value: "" + name: cmp-helm-v2 + repoURL: https://github.com/mirakl/manifests-velero.git + targetRevision: test-lla + revision: rev1 + status: Synced diff --git a/docs/SUPPORT.md b/docs/SUPPORT.md index 48fb337a78954..e0adecf12d38a 100644 --- a/docs/SUPPORT.md +++ b/docs/SUPPORT.md @@ -1,6 +1,7 @@ # Support -1. Make sure you've read [understanding the basics](understand_the_basics.md) the [getting started guide](getting_started.md). -2. Looked for an answer in [the frequently asked questions](faq.md). -3. Ask a question in [the Argo CD Slack channel ⧉](https://argoproj.github.io/community/join-slack). -4. [Read issues, report a bug, or request a feature ⧉](https://github.com/argoproj/argo-cd/issues). +1. Make sure you've read [understanding the basics](understand_the_basics.md) and the [getting started guide](getting_started.md). +1. Looked for an answer in [the frequently asked questions](faq.md). +1. [Read existing issues ⧉](https://github.com/argoproj/argo-cd/issues). +1. Ask a question in [the Argo CD Slack channel ⧉](https://argoproj.github.io/community/join-slack). +1. [Report a bug, or request a feature ⧉](https://github.com/argoproj/argo-cd/issues/new/choose). 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/argocd-arch-authn-authz.jpg b/docs/assets/argocd-arch-authn-authz.jpg new file mode 100644 index 0000000000000..323f95fce1d11 Binary files /dev/null and b/docs/assets/argocd-arch-authn-authz.jpg differ diff --git a/docs/assets/argocd-components.png b/docs/assets/argocd-components.png new file mode 100644 index 0000000000000..35e214a10ca7f Binary files /dev/null and b/docs/assets/argocd-components.png differ diff --git a/docs/assets/argocd-core-components.png b/docs/assets/argocd-core-components.png new file mode 100644 index 0000000000000..f274f7cb821bb Binary files /dev/null and b/docs/assets/argocd-core-components.png differ diff --git a/docs/assets/azure-devops-webhook-config.png b/docs/assets/azure-devops-webhook-config.png new file mode 100644 index 0000000000000..26fb6d0683d63 Binary files /dev/null and b/docs/assets/azure-devops-webhook-config.png differ diff --git a/docs/assets/extra_info-1.png b/docs/assets/extra_info-1.png new file mode 100644 index 0000000000000..8ccf597c0879e Binary files /dev/null and b/docs/assets/extra_info-1.png differ diff --git a/docs/assets/extra_info-2.png b/docs/assets/extra_info-2.png new file mode 100644 index 0000000000000..3dde4e61fa4e0 Binary files /dev/null and b/docs/assets/extra_info-2.png differ diff --git a/docs/assets/extra_info.png b/docs/assets/extra_info.png new file mode 100644 index 0000000000000..c5064762e5138 Binary files /dev/null and b/docs/assets/extra_info.png 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/keycloak-add-client.png b/docs/assets/keycloak-add-client.png index 36d598318cbe3..acdb3e725b8bf 100644 Binary files a/docs/assets/keycloak-add-client.png and b/docs/assets/keycloak-add-client.png differ diff --git a/docs/assets/keycloak-add-client_2.png b/docs/assets/keycloak-add-client_2.png new file mode 100644 index 0000000000000..b765bf89e5698 Binary files /dev/null and b/docs/assets/keycloak-add-client_2.png differ diff --git a/docs/assets/keycloak-add-scope.png b/docs/assets/keycloak-add-scope.png index 200486315e372..b2b759394619d 100644 Binary files a/docs/assets/keycloak-add-scope.png and b/docs/assets/keycloak-add-scope.png differ diff --git a/docs/assets/keycloak-client-scope-selected.png b/docs/assets/keycloak-client-scope-selected.png deleted file mode 100644 index f3ec6ded54c69..0000000000000 Binary files a/docs/assets/keycloak-client-scope-selected.png and /dev/null differ diff --git a/docs/assets/keycloak-client-scope.png b/docs/assets/keycloak-client-scope.png index 04d56583ab926..cd9609b5419b7 100644 Binary files a/docs/assets/keycloak-client-scope.png and b/docs/assets/keycloak-client-scope.png differ diff --git a/docs/assets/keycloak-client-secret.png b/docs/assets/keycloak-client-secret.png index b4679b0e9d4eb..c1a71c3d97f20 100644 Binary files a/docs/assets/keycloak-client-secret.png and b/docs/assets/keycloak-client-secret.png differ diff --git a/docs/assets/keycloak-configure-client.png b/docs/assets/keycloak-configure-client.png index d3805ed05df6a..cd711dfd602bf 100644 Binary files a/docs/assets/keycloak-configure-client.png and b/docs/assets/keycloak-configure-client.png differ diff --git a/docs/assets/keycloak-groups-mapper.png b/docs/assets/keycloak-groups-mapper.png index 3610aa5737a1a..b1ccabb30013a 100644 Binary files a/docs/assets/keycloak-groups-mapper.png and b/docs/assets/keycloak-groups-mapper.png differ diff --git a/docs/assets/keycloak-user-group.png b/docs/assets/keycloak-user-group.png index ff9825b99d708..5c9c21d4f555f 100644 Binary files a/docs/assets/keycloak-user-group.png and b/docs/assets/keycloak-user-group.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/assets/release-action.png b/docs/assets/release-action.png new file mode 100644 index 0000000000000..cadcda53fca09 Binary files /dev/null and b/docs/assets/release-action.png differ diff --git a/docs/assets/versions.js b/docs/assets/versions.js index d3befc5f91dea..7a2392a392dc8 100644 --- a/docs/assets/versions.js +++ b/docs/assets/versions.js @@ -9,16 +9,6 @@ setTimeout(function() { caret.innerHTML = "" caret.classList.add('dropdown-caret') div.querySelector('.rst-current-version').appendChild(caret); - div.querySelector('.rst-current-version').addEventListener('click', function() { - const classes = container.className.split(' '); - const index = classes.indexOf('shift-up'); - if (index === -1) { - classes.push('shift-up'); - } else { - classes.splice(index, 1); - } - container.className = classes.join(' '); - }); } var CSSLink = document.createElement('link'); diff --git a/docs/assets/zitadel-actions.png b/docs/assets/zitadel-actions.png new file mode 100644 index 0000000000000..db0b37245c49e Binary files /dev/null and b/docs/assets/zitadel-actions.png differ diff --git a/docs/assets/zitadel-application-1.png b/docs/assets/zitadel-application-1.png new file mode 100644 index 0000000000000..f69acf9b6939e Binary files /dev/null and b/docs/assets/zitadel-application-1.png differ diff --git a/docs/assets/zitadel-application-2.png b/docs/assets/zitadel-application-2.png new file mode 100644 index 0000000000000..f0b4ff34eabed Binary files /dev/null and b/docs/assets/zitadel-application-2.png differ diff --git a/docs/assets/zitadel-application-3.png b/docs/assets/zitadel-application-3.png new file mode 100644 index 0000000000000..7650217264cbc Binary files /dev/null and b/docs/assets/zitadel-application-3.png differ diff --git a/docs/assets/zitadel-application-4.png b/docs/assets/zitadel-application-4.png new file mode 100644 index 0000000000000..d5660fc4f5f0e Binary files /dev/null and b/docs/assets/zitadel-application-4.png differ diff --git a/docs/assets/zitadel-application-secrets.png b/docs/assets/zitadel-application-secrets.png new file mode 100644 index 0000000000000..9530dc7f1de50 Binary files /dev/null and b/docs/assets/zitadel-application-secrets.png differ diff --git a/docs/assets/zitadel-application-settings.png b/docs/assets/zitadel-application-settings.png new file mode 100644 index 0000000000000..cbe2e62aee738 Binary files /dev/null and b/docs/assets/zitadel-application-settings.png differ diff --git a/docs/assets/zitadel-argocd-login.png b/docs/assets/zitadel-argocd-login.png new file mode 100644 index 0000000000000..b4f2e0b75ae77 Binary files /dev/null and b/docs/assets/zitadel-argocd-login.png differ diff --git a/docs/assets/zitadel-argocd-user-info.png b/docs/assets/zitadel-argocd-user-info.png new file mode 100644 index 0000000000000..88b5a2befa8f2 Binary files /dev/null and b/docs/assets/zitadel-argocd-user-info.png differ diff --git a/docs/assets/zitadel-project-authorizations.png b/docs/assets/zitadel-project-authorizations.png new file mode 100644 index 0000000000000..0ec01f7755dab Binary files /dev/null and b/docs/assets/zitadel-project-authorizations.png differ diff --git a/docs/assets/zitadel-project-roles.png b/docs/assets/zitadel-project-roles.png new file mode 100644 index 0000000000000..ee18d1e1f3dd0 Binary files /dev/null and b/docs/assets/zitadel-project-roles.png differ diff --git a/docs/assets/zitadel-project-settings.png b/docs/assets/zitadel-project-settings.png new file mode 100644 index 0000000000000..ac0c3fa8036c7 Binary files /dev/null and b/docs/assets/zitadel-project-settings.png differ diff --git a/docs/assets/zitadel-project.png b/docs/assets/zitadel-project.png new file mode 100644 index 0000000000000..4ed9b04f87541 Binary files /dev/null and b/docs/assets/zitadel-project.png differ diff --git a/docs/cli_installation.md b/docs/cli_installation.md index 639a9317639fe..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. @@ -115,6 +126,11 @@ $output = "argocd.exe" Invoke-WebRequest -Uri $url -OutFile $output ``` Also please note you will probably need to move the file into your PATH. +Use following command to add Argo CD into environment variables PATH + +```powershell +[Environment]::SetEnvironmentVariable("Path", "$env:Path;C:\Path\To\ArgoCD-CLI", "User") +``` After finishing the instructions above, 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 7b4b44bf9269e..63e3cd901e3d3 100644 --- a/docs/developer-guide/api-docs.md +++ b/docs/developer-guide/api-docs.md @@ -1,6 +1,6 @@ # API Docs -You can find the Swagger docs by setting the path to `/swagger-ui` in your Argo CD UI's. E.g. [http://localhost:8080/swagger-ui](http://localhost:8080/swagger-ui). +You can find the Swagger docs by setting the path to `/swagger-ui` in your Argo CD UI. E.g. [http://localhost:8080/swagger-ui](http://localhost:8080/swagger-ui). ## Authorization @@ -17,4 +17,16 @@ Then pass using the HTTP `Authorization` header, prefixing with `Bearer `: $ curl $ARGOCD_SERVER/api/v1/applications -H "Authorization: Bearer $ARGOCD_TOKEN" {"metadata":{"selfLink":"/apis/argoproj.io/v1alpha1/namespaces/argocd/applications","resourceVersion":"37755"},"items":...} ``` - + +## Services + +### Applications API + +#### 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, the API will return a `404` error. + +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/authz-authn.md b/docs/developer-guide/architecture/authz-authn.md new file mode 100644 index 0000000000000..af32a9176eec9 --- /dev/null +++ b/docs/developer-guide/architecture/authz-authn.md @@ -0,0 +1,109 @@ +# Authentication and Authorization + +This document describes how authentication (authn) and authorization +(authz) are implemented in Argo CD. There is a clear distinction in +the code base of when and how these two security concepts are +enforced. + +## Logical layers + +The diagram bellow suggests 4 different logical layers (represented by +4 boxes: HTTP, gRPC, AuthN and AuthZ) inside Argo CD API server that +collaborate to provide authentication and authorization. + +- **HTTP**: The HTTP layer groups the *logical elements* that + collaborate to handle HTTP requests. Every incoming request reaches + the same HTTP server at the same port (8080). This server will + analyze the request headers and dispatch to the proper internal + server: gRPC or standard HTTP. + +- **gRPC**: The [gRPC][4] layer groups the logical elements responsible for + the gRPC implementation. + +- **AuthN**: The AuthN represents the layer responsible for + authentication. + +- **AuthZ**: The AuthZ represents the layer responsible for + authorization. + +![Argo CD Architecture](../../assets/argocd-arch-authn-authz.jpg) + +## Logical elements + +The logical elements (identified by numbers) can represent an object, +a function or a component in the code base. Note that this particular +distinction is not represented in the diagram. + +Incoming requests can reach Argo CD API server from the web UI as well +as from the `argocd` CLI. The responsibility of the represented +elements are described below with their respective numbers: + +1. **Cmux**: Uses the [cmux][1] library to provide a connection + multiplexer capability making it possible to use the same port to + handle standard HTTP as well as gRPC requests. It is responsible + for inspecting incoming requests and dispatch to appropriate + internal servers. If the request version is `http1.x` it will + delegate to the *http mux*. If the request version is `http2` and + has the header `content-type: application/grpc`, it will delegate + to the *gRPC Server*. + +1. **HTTP mux**: A [standard HTTP multiplexer][8] that will handle non + gRPC requests. It is responsible for serving a unified [REST + API][3] to the web UI exposing all gRPC and non-gRPC services. + +1. **gRPC-gateway**: Uses the [grpc-gateway][2] library to translate + internal gRPC services and expose them as a [REST API][3]. The + great majority of API services in Argo CD are implemented in gRPC. + The grpc-gateway makes it possible to access gRPC services from the + web UI. + +1. **Server**: The internal gRPC Server responsible for handling gRPC + requests. + +1. **AuthN**: Is responsible for invoking the authentication logic. It + is registered as a gRPC interceptor which will automatically + trigger for every gRPC request. + +1. **Session Manager**: Is the object responsible for managing Argo CD + API server session. It provides the functionality to verify the + validity of the authentication token provided in the request. + Depending on how Argo CD is configured it may or may not delegate + to an external AuthN provider to verify the token. + +1. **AuthN Provider**: Describes the component that can be plugged in + Argo CD API server to provide the authentication functionality such + as the login and the token verification process. + +1. **Service Method**: represents the method implementing the business + logic (core functionality) requested. An example of business logic + is: `List Applications`. Service methods are also responsible for + invoking the [RBAC][7] enforcement function to validate if the + authenticated user has permission to execute this method. + +1. **RBAC**: Is a collection of functions to provide the capability to + verify if the user has permission to execute a specific action in + Argo CD. It does so by validating the incoming request action + against predefined [RBAC][7] rules that can be configured in Argo CD + API server as well as in Argo CD `Project` CRD. + +1. **Casbin**: Uses the [Casbin][5] library to enforce [RBAC][7] rules. + +1. **AuthN Middleware**: Is an [HTTP Middleware][6] configured to + invoke the logic to verify the token for HTTP services that are not + implemented as gRPC and requires authentication. + +1. **HTTP Handler**: represents the http handlers responsible for + invoking the business logic (core functionality) requested. An + example of business logic is: `List Applications`. Http handlers + are also responsible for invoking the [RBAC][7] enforcement function to + validate if the authenticated user has permission to execute this + business logic. + +[1]: https://github.com/soheilhy/cmux +[2]: https://github.com/grpc-ecosystem/grpc-gateway +[3]: https://en.wikipedia.org/wiki/Representational_state_transfer +[4]: https://grpc.io/ +[5]: https://casbin.org/ +[6]: https://github.com/golang/go/wiki/LearnServerProgramming#middleware +[7]: https://en.wikipedia.org/wiki/Role-based_access_control +[8]: https://pkg.go.dev/net/http#ServeMux diff --git a/docs/developer-guide/architecture/components.md b/docs/developer-guide/architecture/components.md new file mode 100644 index 0000000000000..e073751da4867 --- /dev/null +++ b/docs/developer-guide/architecture/components.md @@ -0,0 +1,118 @@ +# Component Architecture + +Argo CD is designed with a component based architecture. The goal is +to separate the responsibility in different deployable units in order +to have the following benefits: + +- **Modularity**: Provides great level of flexibility. Components + interact with each other via an interface. This means that as long + as the interface contract is respected, a given component can be + replaced without requiring the rest of the system to adapt. It is + also possible to run the system without certain components if a + specific group of functionality isn't desired. +- **Single responsibility**: Helps to determine where the different + types of functionality should be implemented which drives for + better system cohesiveness. +- **Reusability**: Clearly defined interfaces helps in functionality + discoverability which benefits reusability of services. + +The default Argo CD installation is composed by different components +and different Kubernetes controllers. The controllers aren't +categorized as components as they have proprietary interfaces (CRDs) +and therefore, miss the modular nature. There are more resources +created while installing Argo CD (ConfigMaps, Services, etc), but for +simplicity we are covering just the ones directly related with the +componentized architecture. + +## Dependencies + +The diagram below has represented all dependencies between the +different components used by the default Argo CD installation: + +![Components Diagram](../../assets/argocd-components.png) + +There are 4 logical layers represented in the diagram: + +- **UI**: This is the presentation layer. Users interact with Argo CD + mainly by components from this layer. +- **Application**: The capabilities required to support the components + from the UI layer. +- **Core**: The main Argo CD gitops functionality is implemented by + components and Kubernetes controllers from the Core layer. +- **Infra**: Represent the tools that Argo CD depends on as part of + its infrastructure. + +The logical layers also help making the diagram easier to follow as +dependencies are represented in a top-down relationship. This means +that components from the top layers will be allowed to depend on any +component from any of the bottom layers. However components from the +bottom layers will never depend on any ones from upper layers. + +## Responsibility + +Below you can refer to a brief description of Argo CD components and +its main responsibilities. + +### Webapp + +Argo CD ships with a powerful web interface that allows managing +applications deployed in a given Kubernetes cluster. + +### CLI + +Argo CD provides a CLI that can be used by users to interact with Argo +CD API. The CLI can also be used for automation and scripting. + +### API Server + +Defines the proprietary API exposed by Argo CD that powers the Webapp +and the CLI functionalities. + +### Application Controller + +The Application Controller is responsible for reconciling the +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. + +### ApplicationSet Controller + +The ApplicationSet Controller is responsible for reconciling the +ApplicationSet resource. + +### Repo Server + +Repo Server plays an important role in Argo CD architecture as it is +responsible for interacting with the Git repository to generate the +desired state for all Kubernetes resources that belongs to a given +application. + +### Redis + +Redis is used by Argo CD to provide a cache layer reducing requests +sent to the Kube API as well as to the Git provider. It also supports +a few UI operations. + +### Kube API + +Argo CD controllers will connect to the Kubernetes API in order to run +the reconciliation loop. + +### Git + +As a gitops tool Argo CD requires that the desired state of the +Kubernetes resources to be provided in a Git repository. + +We use "git" here to stand in for an actual git repo, a Helm repo, +or an OCI artifact repo. Argo CD supports all those options. + +### Dex + +Argo CD relies on Dex to provide authentication with external OIDC +providers. However other tools can be used instead of Dex. Check the +[user management +documentation](../../operator-manual/user-management/index.md) for +more details. + + diff --git a/docs/developer-guide/ci.md b/docs/developer-guide/ci.md index 53796c77500e6..921f9d69d4c57 100644 --- a/docs/developer-guide/ci.md +++ b/docs/developer-guide/ci.md @@ -23,13 +23,13 @@ git push origin First, make sure the failing build step succeeds on your machine. Remember the containerized build toolchain is available, too. -If the build is failing at the `Ensure Go modules synchronicity` step, you need to first download all Go dependent modules locally via `go mod download` and then run `go mod tidy` to make sure the dependent Go modules are tidied up. Finally commit and push your changes to `go.mod` and `go.sum` to your branch. +If the build is failing at the `Ensure Go modules synchronicity` step, you need to first download all Go dependent modules locally via `go mod download` and then run `go mod tidy` to make sure the dependent Go modules are tidied up. Finally, commit and push your changes to `go.mod` and `go.sum` to your branch. If the build is failing at the `Build & cache Go code`, you need to make sure `make build-local` runs successfully on your local machine. ### Why does the codegen step fail? -If the codegen step fails with "Check nothing has changed...", chances are high that you did not run `make codegen`, or did not commit the changes it made. You should double check by running `make codegen` followed by `git status` in the local working copy of your branch. Commit any changes and push them to your GH branch to have the CI check it again. +If the codegen step fails with "Check nothing has changed...", chances are high that you did not run `make codegen`, or did not commit the changes it made. You should double-check by running `make codegen` followed by `git status` in the local working copy of your branch. Commit any changes and push them to your GH branch to have the CI check it again. A second common case for this is, when you modified any of the auto generated assets, as these will be overwritten upon `make codegen`. @@ -66,7 +66,7 @@ make builder-image IMAGE_NAMESPACE=argoproj IMAGE_TAG=v1.0.0 ## Public CD Every commit to master is built and published to `ghcr.io/argoproj/argo-cd/argocd:-`. The list of images is available at -https://github.com/argoproj/argo-cd/packages. +[https://github.com/argoproj/argo-cd/packages](https://github.com/argoproj/argo-cd/packages). !!! note GitHub docker registry [requires](https://github.community/t5/GitHub-Actions/docker-pull-from-public-GitHub-Package-Registry-fail-with-quot/m-p/32888#M1294) authentication to read diff --git a/docs/developer-guide/code-contributions.md b/docs/developer-guide/code-contributions.md index b57d9df6d8ae6..2d28aaa956b48 100644 --- a/docs/developer-guide/code-contributions.md +++ b/docs/developer-guide/code-contributions.md @@ -103,10 +103,12 @@ Design documents are usually submitted as PR and use [this template](https://git Our community regularly meets virtually to discuss issues, ideas and enhancements around Argo CD. We do invite you to join this virtual meetings if you want to bring up certain things (including your enhancement proposals), participate in our triaging or just want to get to know other contributors. -The current cadence of our meetings is weekly, every Thursday at 4:15pm UTC (8:15am Pacific, 11:15am Eastern, 5:15pm Central European, 9:45pm Indian). We use Zoom to conduct these meetings. +The current cadence of our meetings is weekly, every Thursday at 8:15AM Pacific Time ([click here to check in your current timezone][1]). We use Zoom to conduct these meetings. * [Agenda document (Google Docs, includes Zoom link)](https://docs.google.com/document/d/1xkoFkVviB70YBzSEa4bDnu-rUZ1sIFtwKKG1Uw8XsY8) If you want to discuss something, we kindly ask you to put your item on the [agenda](https://docs.google.com/document/d/1xkoFkVviB70YBzSEa4bDnu-rUZ1sIFtwKKG1Uw8XsY8) -for one of the upcoming meetings so that we can plan in the time for discussing about it. \ No newline at end of file +for one of the upcoming meetings so that we can plan in the time for discussing it. + +[1]: https://www.timebie.com/std/pacific.php?q=081500 diff --git a/docs/developer-guide/contributors-quickstart.md b/docs/developer-guide/contributors-quickstart.md index 821fc36f3eabd..68cda35b6d08e 100644 --- a/docs/developer-guide/contributors-quickstart.md +++ b/docs/developer-guide/contributors-quickstart.md @@ -9,22 +9,15 @@ and the [toolchain guide](toolchain-guide.md). ### Install Go -- Install version 1.18 or newer (Verify version by running `go version`) + -- Get current value of `GOPATH` env: - ```shell - go env | grep path - ``` -- Change directory into that path - ```shell - cd - ``` +Install Go with a version equal to or greater than the version listed in `go.mod` (verify go version with `go version`). ### Clone the Argo CD repo ```shell -mkdir -p src/github.com/argoproj/ && -cd src/github.com/argoproj && +mkdir -p $GOPATH/src/github.com/argoproj/ && +cd $GOPATH/src/github.com/argoproj && git clone https://github.com/argoproj/argo-cd.git ``` @@ -32,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 @@ -71,7 +77,7 @@ cd argo-cd make start-local ARGOCD_GPG_ENABLED=false ``` -- Navigate to to the ArgoCD UI on browser +- Navigate to [localhost:4000](http://localhost:4000) in your browser to load the Argo CD UI - It may take a few minutes for the UI to be responsive !!! note diff --git a/docs/developer-guide/debugging-remote-environment.md b/docs/developer-guide/debugging-remote-environment.md index 7fe7f18260205..5548d3444af8c 100644 --- a/docs/developer-guide/debugging-remote-environment.md +++ b/docs/developer-guide/debugging-remote-environment.md @@ -28,7 +28,7 @@ telepresence intercept argocd-server --port 8080:http --env-file .envrc.remote # * `--port` forwards traffic of remote port http to 8080 locally (use `--port 8080:https` if argocd-server terminates TLS) * `--env-file` writes all the environment variables of the remote pod into a local file, the variables are also set on the subprocess of the `--run` command -With this, any traffic that hits your argocd-server service in the cluster (e.g through a LB / ingress) will be forwarded to your laptop on port 8080. So that you can now start argocd-server locally to debug or test new code. If you launch argocd-server using the environment variables in `.envrc.remote`, he is able to fetch all the configmaps, secrets and so one from the cluster and transparently connect to the other microservices so that no further configuration should be neccesary and he behaves exactly the same as in the cluster. +With this, any traffic that hits your argocd-server service in the cluster (e.g. through a LB / ingress) will be forwarded to your laptop on port 8080. So that you can now start argocd-server locally to debug or test new code. If you launch argocd-server using the environment variables in `.envrc.remote`, it is able to fetch all the configmaps, secrets and so on from the cluster and transparently connect to the other microservices so that no further configuration should be necessary, and it behaves exactly the same as in the cluster. List current status of Telepresence using: ```shell @@ -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/proxy-extensions.md b/docs/developer-guide/extensions/proxy-extensions.md new file mode 100644 index 0000000000000..c53946cade95f --- /dev/null +++ b/docs/developer-guide/extensions/proxy-extensions.md @@ -0,0 +1,335 @@ +# Proxy Extensions +*Current Status: [Alpha][1] (Since v2.7.0)* + +## Overview + +With UI extensions it is possible to enhance Argo CD web interface to +provide valuable data to the user. However the data is restricted to +the resources that belongs to the Application. With proxy extensions +it is also possible to add additional functionality that have access +to data provided by backend services. In this case Argo CD API server +acts as a reverse-proxy authenticating and authorizing incoming +requests before forwarding to the backend service. + +## Configuration + +As proxy extension is in [Alpha][1] phase, the feature is disabled by +default. To enable it, it is necessary to configure the feature flag +in Argo CD command parameters. The easiest way to properly enable +this feature flag is by adding the `server.enable.proxy.extension` key +in the existing `argocd-cmd-params-cm`. For example: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cmd-params-cm + namespace: argocd +data: + server.enable.proxy.extension: "true" +``` + +Once the proxy extension is enabled, it can be configured in the main +Argo CD configmap ([argocd-cm][2]). + +The example below demonstrates all possible configurations available +for proxy extensions: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cm + namespace: argocd +data: + extension.config: | + extensions: + - name: httpbin + backend: + connectionTimeout: 2s + keepAlive: 15s + idleConnectionTimeout: 60s + maxIdleConnections: 30 + services: + - url: http://httpbin.org + headers: + - name: some-header + value: '$some.argocd.secret.key' + cluster: + name: some-cluster + server: https://some-cluster +``` + +Note: There is no need to restart Argo CD Server after modifiying the +`extension.config` entry in Argo CD configmap. Changes will be +automatically applied. A new proxy registry will be built making +all new incoming extensions requests (`/extensions/*`) to +respect the new configuration. + +Every configuration entry is explained below: + +#### `extensions` (*list*) + +Defines configurations for all extensions enabled. + +#### `extensions.name` (*string*) +(mandatory) + +Defines the endpoint that will be used to register the extension +route. For example, if the value of the property is `extensions.name: +my-extension` then the backend service will be exposed under the +following url: + + /extensions/my-extension + +#### `extensions.backend.connectionTimeout` (*duration string*) +(optional. Default: 2s) + +Is the maximum amount of time a dial to the extension server will wait +for a connect to complete. + +#### `extensions.backend.keepAlive` (*duration string*) +(optional. Default: 15s) + +Specifies the interval between keep-alive probes for an active network +connection between the API server and the extension server. + +#### `extensions.backend.idleConnectionTimeout` (*duration string*) +(optional. Default: 60s) + +Is the maximum amount of time an idle (keep-alive) connection between +the API server and the extension server will remain idle before +closing itself. + +#### `extensions.backend.maxIdleConnections` (*int*) +(optional. Default: 30) + +Controls the maximum number of idle (keep-alive) connections between +the API server and the extension server. + +#### `extensions.backend.services` (*list*) + +Defines a list with backend url by cluster. + +#### `extensions.backend.services.url` (*string*) +(mandatory) + +Is the address where the extension backend must be available. + +#### `extensions.backend.services.headers` (*list*) + +If provided, the headers list will be added on all outgoing requests +for this service config. Existing headers in the incoming request with +the same name will be overriden by the one in this list. Reserved header +names will be ignored (see the [headers](#incoming-request-headers) below). + +#### `extensions.backend.services.headers.name` (*string*) +(mandatory) + +Defines the name of the header. It is a mandatory field if a header is +provided. + +#### `extensions.backend.services.headers.value` (*string*) +(mandatory) + +Defines the value of the header. It is a mandatory field if a header is +provided. The value can be provided as verbatim or as a reference to an +Argo CD secret key. In order to provide it as a reference, it is +necessary to prefix it with a dollar sign. + +Example: + + value: '$some.argocd.secret.key' + +In the example above, the value will be replaced with the one from +the argocd-secret with key 'some.argocd.secret.key'. + +#### `extensions.backend.services.cluster` (*object*) +(optional) + +If provided, and multiple services are configured, will have to match +the application destination name or server to have requests properly +forwarded to this service URL. If there are multiple backends for the +same extension this field is required. In this case at least one of +the two will be required: name or server. It is better to provide both +values to avoid problems with applications unable to send requests to +the proper backend service. If only one backend service is +configured, this field is ignored, and all requests are forwarded to +the configured one. + +#### `extensions.backend.services.cluster.name` (*string*) +(optional) + +It will be matched with the value from +`Application.Spec.Destination.Name` + +#### `extensions.backend.services.cluster.server` (*string*) +(optional) + +It will be matched with the value from +`Application.Spec.Destination.Server`. + +## Usage + +Once a proxy extension is configured it will be made available under +the `/extensions/` endpoint exposed by Argo CD API +server. The example above will proxy requests to +`/extensions/httpbin/` to `http://httpbin.org`. + +The diagram below illustrates an interaction possible with this +configuration: + +``` + ┌─────────────┐ + │ Argo CD UI │ + └────┬────────┘ + │ ▲ + GET /extensions/httpbin/anything │ │ 200 OK + + authn/authz headers │ │ + ▼ │ + ┌─────────┴────────┐ + │Argo CD API Server│ + └──────┬───────────┘ + │ ▲ + GET http://httpbin.org/anything │ │ 200 OK + │ │ + ▼ │ + ┌────────┴────────┐ + │ Backend Service │ + └─────────────────┘ +``` + +### Incoming Request Headers + +Note that Argo CD API Server requires additional HTTP headers to be +sent in order to enforce if the incoming request is authenticated and +authorized before being proxied to the backend service. The headers +are documented below: + +#### `Cookie` + +Argo CD UI keeps the authentication token stored in a cookie +(`argocd.token`). This value needs to be sent in the `Cookie` header +so the API server can validate its authenticity. + +Example: + + Cookie: argocd.token=eyJhbGciOiJIUzI1Ni... + +The entire Argo CD cookie list can also be sent. The API server will +only use the `argocd.token` attribute in this case. + +#### `Argocd-Application-Name` (mandatory) + +This is the name of the project for the application for which the +extension is being invoked. The header value must follow the format: +`":"`. + +Example: + + Argocd-Application-Name: namespace:app-name + +#### `Argocd-Project-Name` (mandatory) + +The logged in user must have access to this project in order to be +authorized. + +Example: + + Argocd-Project-Name: default + +Argo CD API Server will ensure that the logged in user has the +permission to access the resources provided by the headers above. The +validation is based on pre-configured [Argo CD RBAC rules][3]. The +same headers are also sent to the backend service. The backend service +must also validate if the validated headers are compatible with the +rest of the incoming request. + +### Outgoing Requests Headers + +Requests sent to backend services will be decorated with additional +headers. The outgoing request headers are documented below: + +#### `Argocd-Target-Cluster-Name` + +Will be populated with the value from `app.Spec.Destination.Name` if +it is not empty string in the application resource. + +#### `Argocd-Target-Cluster-URL` + +Will be populated with the value from `app.Spec.Destination.Server` if +it is not empty string is the Application resource. + +Note that additional pre-configured headers can be added to outgoing +request. See [backend service headers](#extensionsbackendservicesheaders-list) +section for more details. + +### Multi Backend Use-Case + +In some cases when Argo CD is configured to sync with multiple remote +clusters, there might be a need to call a specific backend service in +each of those clusters. The proxy-extension can be configured to +address this use-case by defining multiple services for the same +extension. Consider the following configuration as an example: + +```yaml +extension.config: | + extensions: + - name: some-extension + backend: + services: + - url: http://extension-name.com:8080 + cluster + name: kubernetes.local + - url: https://extension-name.ppd.cluster.k8s.local:8080 + cluster + server: user@ppd.cluster.k8s.local +``` + +In the example above, the API server will inspect the Application +destination to verify which URL should be used to proxy the incoming +request to. + +## Security + +When a request to `/extensions/*` reaches the API Server, it will +first verify if it is authenticated with a valid token. It does so by +inspecting if the `Cookie` header is properly sent from Argo CD UI +extension. + +Once the request is authenticated it is then verified if the +user has permission to invoke this extension. The permission is +enforced by Argo CD RBAC configuration. The details about how to +configure the RBAC for proxy-extensions can be found in the [RBAC +documentation][3] page. + +Once the request is authenticated and authorized by the API server, it +is then sanitized before being sent to the backend service. The +request sanitization will remove sensitive information from the +request like the `Cookie` and `Authorization` headers. + +A new `Authorization` header can be added to the outgoing request by +defining it as a header in the `extensions.backend.services.headers` +configuration. Consider the following example: + +```yaml +extension.config: | + extensions: + - name: some-extension + backend: + services: + - url: http://extension-name.com:8080 + headers: + - name: Authorization + value: '$some-extension.authorization.header' +``` + +In the example above, all requests sent to +`http://extension-name.com:8080` will have an additional +`Authorization` header. The value of this header will be the one from +the [argocd-secret](../../operator-manual/argocd-secret-yaml.md) with +key `some-extension.authorization.header` + +[1]: https://github.com/argoproj/argoproj/blob/master/community/feature-status.md +[2]: https://argo-cd.readthedocs.io/en/stable/operator-manual/argocd-cm.yaml +[3]: ../../operator-manual/rbac.md#the-extensions-resource diff --git a/docs/developer-guide/extensions/ui-extensions.md b/docs/developer-guide/extensions/ui-extensions.md new file mode 100644 index 0000000000000..8d3d9dc4a3882 --- /dev/null +++ b/docs/developer-guide/extensions/ui-extensions.md @@ -0,0 +1,160 @@ +# UI Extensions + +Argo CD web user interface can be extended with additional UI elements. Extensions should be delivered as a javascript file +in the `argocd-server` Pods that are placed in the `/tmp/extensions` directory and starts with `extension` prefix ( matches to `^extension(.*)\.js$` regex ). + +``` +/tmp/extensions +├── example1 +│   └── extension-1.js +└── example2 + └── extension-2.js +``` + +Extensions are loaded during initial page rendering and should register themselves using API exposed in the `extensionsAPI` global variable. (See +corresponding extension type details for additional information). + +The extension should provide a React component that is responsible for rendering the UI element. Extension should not bundle the React library. +Instead extension should use the `react` global variable. You can leverage `externals` setting if you are using webpack: + +```js +externals: { + react: "React"; +} +``` + +## Resource Tab Extensions + +Resource Tab extensions is an extension that provides an additional tab for the resource sliding panel at the Argo CD Application details page. + +The resource tab extension should be registered using the `extensionsAPI.registerResourceExtension` method: + +```typescript +registerResourceExtension(component: ExtensionComponent, group: string, kind: string, tabTitle: string) +``` + +- `component: ExtensionComponent` is a React component that receives the following properties: + + - application: Application - Argo CD Application resource; + - 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) + +- `group: string` - the glob expression that matches the group of the resource; note: use globstar (`**`) to match all groups including empty string; +- `kind: string` - the glob expression that matches the kind of the resource; +- `tabTitle: string` - the extension tab title. +- `opts: Object` - additional options: + - `icon: string` - the class name the represents the icon from the [https://fontawesome.com/](https://fontawesome.com/) library (e.g. 'fa-calendar-alt'); + +Below is an example of a resource tab extension: + +```javascript +((window) => { + const component = () => { + return React.createElement("div", {}, "Hello World"); + }; + window.extensionsAPI.registerResourceExtension( + component, + "*", + "*", + "Nice extension" + ); +})(window); +``` + +## System Level Extensions + +Argo CD allows you to add new items to the sidebar that will be displayed as a new page with a custom component when clicked. The system level extension should be registered using the `extensionsAPI.registerSystemLevelExtension` method: + +```typescript +registerSystemLevelExtension(component: ExtensionComponent, title: string, options: {icon?: string}) +``` + +Below is an example of a simple system level extension: + +```typescript +((window) => { + const component = () => { + return React.createElement( + "div", + { style: { padding: "10px" } }, + "Hello World" + ); + }; + window.extensionsAPI.registerSystemLevelExtension( + component, + "Test Ext", + "/hello", + "fa-flask" + ); +})(window); +``` + +## Application Tab Extensions + +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/faq.md b/docs/developer-guide/faq.md index 0a8d936477bb4..5d9dda31949f7 100644 --- a/docs/developer-guide/faq.md +++ b/docs/developer-guide/faq.md @@ -6,11 +6,20 @@ Sure thing! You can either open an Enhancement Proposal in our GitHub issue tracker or you can [join us on Slack](https://argoproj.github.io/community/join-slack) in channel #argo-contributors to discuss your ideas and get guidance for submitting a PR. +!!! note + Regular [contributor meetings](https://argo-cd.readthedocs.io/en/latest/developer-guide/code-contributions/#regular-contributor-meeting) are held weekly. Please follow the link for more details. + ### No one has looked at my PR yet. Why? -As we have limited manpower, it can sometimes take a while for someone to respond to your PR. Especially, when your PR contains complex or non-obvious changes. Please bear with us, we try to look at every PR that we receive. +As we have limited resources, it can sometimes take a while for someone to respond to your PR. Especially, when your PR contains complex or non-obvious changes. Please bear with us, we try to look at every PR that we receive. Kindly ensure all applicable requirements have been met in your PR checklist. + +### How do I get my PR labeled `ready-for-review` ? + +Conventionally an initial review is performed from a Argo member or reviewer. Once the initial review is approved, it can be labeled `ready-for-review` and then added to the [Argo CD Review](https://github.com/orgs/argoproj/projects/28) Github project. Details of the project dashboard can be found [here](https://github.com/orgs/argoproj/projects/28?pane=info). + +High quality reviews are extremely encouraged from the community. A member/reviewer may work with a community reviewer to get a PR labeled `ready-for-review`. It can then be added to the project dashboard and marked `Community Reviewed`. -### Why has my PR been declined? I put much work in it! +### Why has my PR been declined? I put so much work into it! We appreciate that you have put your valuable time and know how into a contribution. Alas, some changes do not fit into the overall ArgoCD philosophy, and therefore can't be merged into the official ArgoCD source tree. diff --git a/docs/developer-guide/release-process-and-cadence.md b/docs/developer-guide/release-process-and-cadence.md index 71e3072aed58c..3bedd35ff4b3c 100644 --- a/docs/developer-guide/release-process-and-cadence.md +++ b/docs/developer-guide/release-process-and-cadence.md @@ -6,12 +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) | -| v2.8 | Monday, Jun. 5, 2023 | Monday, Jun. 19, 2023 | Monday, Aug. 7, 2023 | -| v2.9 | Monday, Sep. 4, 2023 | Monday, Sep. 18, 2023 | Monday, Nov. 6, 2023 | +| 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. @@ -20,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: @@ -38,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 @@ -76,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. Read more about supported versions in the [security policy for Argo CD](https://github.com/argoproj/argo-cd/security/policy#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/releasing.md b/docs/developer-guide/releasing.md index ed8297fb0e5c5..bb51ebfa8d14b 100644 --- a/docs/developer-guide/releasing.md +++ b/docs/developer-guide/releasing.md @@ -1,113 +1,86 @@ # Releasing -## Automated release procedure +## Introduction -Starting from `release-1.6` branch, ArgoCD can be released in an automated fashion -using GitHub actions. The release process takes about 20 minutes, sometimes a -little less, depending on the performance of GitHub Actions runners. +Argo CD is released in a 2 step automated fashion using GitHub actions. The release process takes about 60 minutes, +sometimes a little less, depending on the performance of GitHub Actions runners. The target release branch must already exist in the GitHub repository. If you for -example want to create a release `v1.7.0`, the corresponding release branch -`release-1.7` needs to exist, otherwise, the release cannot be built. Also, +example want to create a release `v2.7.0`, the corresponding release branch +`release-2.7` needs to exist, otherwise, the release cannot be built. Also, the trigger tag should always be created in the release branch, checked out in your local repository clone. Before triggering the release automation, the `CHANGELOG.md` should be updated with the latest information, and this change should be committed and pushed to the GitHub repository to the release branch. Afterward, the automation can be -triggered. +triggered. This will be automated in the very near future. **Manual steps before release creation:** * Update `CHANGELOG.md` with changes for this release * Commit & push changes to `CHANGELOG.md` -* Prepare release notes (save to some file, or copy from Changelog) -**The automation will perform the following steps:** +**The `Init ARGOCD Release` workflow will perform the following steps:** * Update `VERSION` file in the release branch * Update manifests with image tags of the new version in the release branch -* Build the Docker image and push to Docker Hub -* Create a release tag in the GitHub repository -* Create a GitHub release and attach the required assets to it (CLI binaries, ...) +* Create a pull request to submit the above changes -Finally, it will the remove trigger tag from the repository again. +**The `Publish ArgoCD Release` workflow will perform the following steps:** -Automation supports both, GA and pre-releases. The automation is triggered by -pushing a tag to the repository. The tag must be in one of the following formats -to trigger the GH workflow: +* Build, push, and signs the container image to Quay.io +* Generate a provenance for the container image +* Builds the CLI binaries, release-notes, and then creates a GitHub release and attaches the required assets. +* Generate a provenance for the CLI binaries +* Generate and sign a sbom +* Update the stable tag when applicable +* Update `VERSION` file in the master branch when a new release is GA -* GA: `release-v..` -* Pre-release: `release-v..-rc` +## Steps -The tag must be an annotated tag, and it must contain the release notes in the -commit message. Please note that Markdown uses `#` character for formatting, but -Git uses it as comment char. To solve this, temporarily switch Git's comment char -to something else, the `;` character is recommended. +### Step 1 - Update Version and Manifest -For example, consider you have configured the Git remote for the repository to -`github.com/argoproj/argo-cd` to be named `upstream` and are in your locally -checked out repo: +1. Ensure that the TARGET_BRANCH already exist. +2. Visit the [Release GitHub Action](https://github.com/argoproj/argo-cd/actions/workflows/init-release.yaml) +and choose which branch you would like to work from. +3. Enter the TARGET_BRANCH to checkout. +4. Enter the TARGET_VERSION that will be used to build manifest and `VERSION` file. (e.g `2.7.0-rc1`) -```shell -git config core.commentChar ';' -git tag -a -F /path/to/release-notes.txt release-v1.6.0-rc2 -git push upstream release-v1.6.0-rc2 -git tag -d release-v1.6.0-rc2 -git config core.commentChar '#' +![GitHub Release Action](../assets/release-action.png) -``` +When the action is completed a pull request will be generated that contains the updated manifest and `Version` file. + +5. Merge the pull request and proceed to step 2. -For convenience, there is a shell script in the tree that ensures all the -pre-requisites are met and that the trigger is well-formed before pushing -it to the GitHub repo. +### Step 2 - Tag Release Branch -In summary, the modifications it does are: +The steps below need to be executed by someone with write access in Argo CD upstream repo. -* Create annotated trigger tag in your local repository -* Push the tag to the GitHub repository to trigger the workflow -* Remove trigger tag from your local repository +1. Checkout the release branch. Example: `git fetch upstream && git + checkout release-2.7` +2. Run the script found at `hack/trigger-release.sh` as follows: -The script can be found at `hack/trigger-release.sh` and is used as follows: +```shell +./hack/trigger-release.sh +``` +Example: ```shell -./hack/trigger-release.sh [] +./hack/trigger-release.sh v2.7.2 upstream ``` -The `` identifier needs to be specified **without** the `release-` -prefix, so just specify it as `v1.6.0-rc2` for example. The `` -specifies the name of the remote used to push to the GitHub repository. - -If you omit the ``, an editor will pop-up asking you to -enter the tag's annotation so you can paste the release notes, save, and exit. -It will also take care of temporarily configuring the `core.commentChar` and -setting it back to its original state. - -:warning: - It is strongly recommended to use this script to trigger the workflow - instead of manually pushing a tag to the repository. - -Once the trigger tag is pushed to the repo, the GitHub workflow will start -execution. You can follow its progress under the `Actions` tab, the name of the -action is `Create release`. Don't get confused by the name of the running -workflow, it will be the commit message of the latest commit to the `master` -branch, this is a limitation of GH actions. - -The workflow performs necessary checks so that the release can be successfully -built before the build actually starts. It will error when one of the -prerequisites is not met, or if the release cannot be built (i.e. already -exists, release notes invalid, etc etc). You can see a summary of what has -failed in the job's overview page and more detailed errors in the output -of the step that has failed. - -:warning: +!!! tip + The tag must be in one of the following formats to trigger the GH workflow:
+ * GA: `v..`
+ * Pre-release: `v..-rc` + +Once the script is executed successfully, a GitHub workflow will start +execution. You can follow its progress under the [Actions](https://github.com/argoproj/argo-cd/actions/workflows/release.yaml) tab, the name of the action is `Publish ArgoCD Release`. + +!!! warning You cannot perform more than one release on the same release branch at the - same time. For example, both `v1.6.0` and `v1.6.1` would operate on the - `release-1.6` branch. If you submit `v1.6.1` while `v1.6.0` is still - executing, the release automation will not execute. You have to either - cancel `v1.6.0` before submitting `v1.6.1` or wait until it has finished. - You can execute releases on different release branches simultaneously, for - example, `v1.6.0` and `v1.7.0-rc1`, without problems. + same time. ### Verifying automated release @@ -118,119 +91,26 @@ checks to see if the release came out correctly: * Check [https://github.com/argoproj/argo-cd/releases](https://github.com/argoproj/argo-cd/releases) to see if the release has been correctly created and if all required assets are attached. -* Check whether the image has been published on DockerHub correctly +* Check whether the image has been published on Quay.io correctly ### If something went wrong If something went wrong, damage should be limited. Depending on the steps that have been performed, you will need to manually clean up. -* Delete the release tag (e.g. `v1.6.0-rc2`) created in the GitHub repository. This - will immediately set the release (if created) to `draft` status, invisible to the - general public. -* Delete the draft release (if created) from the `Releases` page on GitHub -* If Docker image has been pushed to DockerHub, delete it -* If commits have been performed to the release branch, revert them. Paths that could have been committed to are: - * `VERSION` - * `manifests/*` - -### Post-process manual steps - -For now, the only manual steps left are to - -* update stable tag in the GitHub repository to point to new the release (if appropriate) -* update the `VERSION` file on `master` if this is a new major release - -These may be automated as well in the future. - -## Manual releasing - -The automatic release process does not interfere with the manual release process, since -the trigger tag does not match a normal release tag. If you prefer to perform, -manual release or if automatic release is for some reason broken, these are the -steps: - -Make sure you are logged into Docker Hub: - -```bash -docker login -``` - -Export the upstream repository and branch name, e.g.: - -```bash -REPO=upstream ;# or origin -BRANCH=release-1.3 -``` - -Set the `VERSION` environment variable: - -```bash -# release candidate -VERSION=v1.3.0-rc1 -# GA release -VERSION=v1.3.1 -``` - -Update `VERSION` and manifests with the new version: - -```bash -git checkout $BRANCH -echo ${VERSION:1} > VERSION -make dev-tools-image -make manifests IMAGE_TAG=$VERSION -git commit -am "Update manifests to $VERSION" -git tag $VERSION -``` - -Build, and push release to Docker Hub - -```bash -git clean -fd -make release IMAGE_NAMESPACE=argoproj IMAGE_TAG=$VERSION DOCKER_PUSH=true -git push $REPO $BRANCH -git push $REPO $VERSION -``` - -Update [GitHub releases](https://github.com/argoproj/argo-cd/releases) with: - -* Getting started (copy from the previous release) -* Changelog -* Binaries (e.g. `dist/argocd-darwin-amd64`). - -## Update brew formulae (manual) - -If GA, update the Brew formula: - -```bash -brew bump-formula-pr argocd --version ${VERSION:1} -``` - -## Update stable tag (manual) - -If GA, update `stable` tag: - -```bash -git tag stable --force && git push $REPO stable --force -``` - -## Verify release +* If the container image has been pushed to Quay.io, delete it +* Delete the release (if created) from the `Releases` page on GitHub -Locally: +### Manual releasing -```bash -kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/$VERSION/manifests/install.yaml -``` - -Follow the [Getting Started Guide](../getting_started/). - -If GA: - -```bash -brew upgrade argocd -/usr/local/bin/argocd version -``` +The release process does not allow a manual release process. Image signatures and provenance need to be created using GitHub Actions. -Sync Argo CD in [https://cd.apps.argoproj.io/applications/argo-cd](https://cd.apps.argoproj.io/applications/argo-cd). +## Notable files that involve the release process. -Deploy the [site](site.md). +| File | Description | +|------------------------------------|--------------------------------------------------------| +|goreleaser.yaml |Config to build CLI binaries, checksums, release-notes | +|.github/workflows/image-reuse.yaml |Reusable workflow used to generate container images | +|.github/workflows/init-release.yaml |Used to generate manifest and `VERSION` file | +|.github/workflows/release.yaml |Build image, CLI binaries, provenances, sbom, post jobs | +|./hack/trigger-release.sh |Ensures all pre-requistes are met and pushes the tag | diff --git a/docs/developer-guide/running-locally.md b/docs/developer-guide/running-locally.md index f4f5dd646da20..25f4510e9e18a 100644 --- a/docs/developer-guide/running-locally.md +++ b/docs/developer-guide/running-locally.md @@ -2,7 +2,7 @@ ## Run Argo CD outside of Kubernetes -During development, it might be viable to run Argo CD outside of a Kubernetes cluster. This will greatly speed up development, as you don't have to constantly build, push and install new Argo CD Docker images with your latest changes. +During development, it might be viable to run Argo CD outside a Kubernetes cluster. This will greatly speed up development, as you don't have to constantly build, push and install new Argo CD Docker images with your latest changes. You will still need a working Kubernetes cluster, as described in the [Toolchain Guide](toolchain-guide.md), where Argo CD will store all of its resources and configuration. @@ -179,7 +179,7 @@ For your final tests, it might be necessary to build your own images and run the ### Create Docker account and login -You might need to create a account on [Docker Hub](https://hub.docker.com) if you don't have one already. Once you created your account, login from your development environment: +You might need to create an account on [Docker Hub](https://hub.docker.com) if you don't have one already. Once you created your account, login from your development environment: ```bash docker login diff --git a/docs/developer-guide/site.md b/docs/developer-guide/site.md index c1ff0cac6251e..33106cd5fa939 100644 --- a/docs/developer-guide/site.md +++ b/docs/developer-guide/site.md @@ -2,24 +2,19 @@ ## Developing And Testing -The web site is build using `mkdocs` and `mkdocs-material`. +The website is built using `mkdocs` and `mkdocs-material`. To test: ```bash 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/). +Make a change to documentation and the website will rebuild and refresh the view. -Check for broken external links: - -```bash -make lint-docs -``` - -## Deploying - +Before submitting a PR build the website, to verify that there are no errors building the site ```bash -make publish-docs +make build-docs ``` ## Analytics @@ -27,4 +22,4 @@ make publish-docs !!! 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/test-e2e.md b/docs/developer-guide/test-e2e.md index 3d46fd55fdba9..477723016bd75 100644 --- a/docs/developer-guide/test-e2e.md +++ b/docs/developer-guide/test-e2e.md @@ -33,7 +33,7 @@ Some effort has been made to balance test isolation with speed. Tests are isolat * A random 5 character ID. * A unique Git repository containing the `testdata` in `/tmp/argocd-e2e/${id}`. * A namespace `argocd-e2e-ns-${id}`. -* An primary name for the app `argocd-e2e-${id}`. +* A primary name for the app `argocd-e2e-${id}`. ## Troubleshooting diff --git a/docs/developer-guide/toolchain-guide.md b/docs/developer-guide/toolchain-guide.md index c529416a2634e..9bba72b456f71 100644 --- a/docs/developer-guide/toolchain-guide.md +++ b/docs/developer-guide/toolchain-guide.md @@ -53,7 +53,7 @@ The following read will help you to submit a PR that meets the standards of our Please use a meaningful and concise title for your PR. This will help us to pick PRs for review quickly, and the PR title will also end up in the Changelog. -We use the [Semantic PR title checker](https://github.com/zeke/semantic-pull-requests) to categorize your PR into one of the following categories: +We use [PR title checker](https://github.com/marketplace/actions/pr-title-checker) to categorize your PR into one of the following categories: * `fix` - Your PR contains one or more code bug fixes * `feat` - Your PR contains a new feature @@ -138,6 +138,14 @@ The following steps are required no matter whether you chose to use a virtualize export SUDO=sudo ``` + If you have podman installed, you can also leverage its rootless mode. In + order to use podman for running and testing Argo CD locally, set the + `DOCKER` environment variable to `podman` before you run `make`, e.g. + + ``` + DOCKER=podman make start + ``` + ### Clone the Argo CD repository from your personal fork on GitHub * `mkdir -p ~/go/src/github.com/argoproj` @@ -157,9 +165,9 @@ Make sure you fulfill the pre-requisites above and run some preliminary tests. N * Run `docker version` * Run `go version` -### Build (or pull) the required Docker image +### Build the required Docker image -Build the required Docker image by running `make test-tools-image` or pull the latest version by issuing `docker pull argoproj/argocd-test-tools`. +Build the required Docker image by running `make test-tools-image`. This image offers the environment of the virtualized toolchain. The `Dockerfile` used to build these images can be found at `test/container/Dockerfile`. @@ -178,7 +186,7 @@ you should edit your `~/.kube/config` and modify the `server` option to point to ### Using k3d -[k3d](https://github.com/rancher/k3d) is a lightweight wrapper to run [k3s](https://github.com/rancher/k3s), a minimal Kubernetes distribution, in docker. Because it's running in a docker container, you're dealing with docker's internal networking rules when using k3d. A typical Kubernetes cluster running on your local machine is part of the same network that you're on so you can access it using **kubectl**. However, a Kubernetes cluster running within a docker container (in this case, the one launched by make) cannot access 0.0.0.0 from inside the container itself, when 0.0.0.0 is a network resource outside the container itself (and/or the container's network). This is the cost of a fully self-contained, disposable Kubernetes cluster. The following steps should help with a successful `make verify-kube-connect` execution. +[k3d](https://github.com/rancher/k3d) is a lightweight wrapper to run [k3s](https://github.com/rancher/k3s), a minimal Kubernetes distribution, in docker. Because it's running in a docker container, you're dealing with docker's internal networking rules when using k3d. A typical Kubernetes cluster running on your local machine is part of the same network that you're on, so you can access it using **kubectl**. However, a Kubernetes cluster running within a docker container (in this case, the one launched by make) cannot access 0.0.0.0 from inside the container itself, when 0.0.0.0 is a network resource outside the container itself (and/or the container's network). This is the cost of a fully self-contained, disposable Kubernetes cluster. The following steps should help with a successful `make verify-kube-connect` execution. 1. Find your host IP by executing `ifconfig` on Mac/Linux and `ipconfig` on Windows. For most users, the following command works to find the IP address. @@ -205,10 +213,11 @@ you should edit your `~/.kube/config` and modify the `server` option to point to 4. Finally, so that you don't have to keep updating your kube-config whenever you spin up a new k3d cluster, add `--api-port $IP:6550` to your **k3d cluster create** command, where $IP is the value from step 1. An example command is provided here: ``` -k3d cluster create my-cluster --wait --k3s-server-arg '--disable=traefik' --api-port $IP:6550 -p 443:443@loadbalancer +k3d cluster create my-cluster --wait --k3s-arg '--disable=traefik@server:*' --api-port $IP:6550 -p 443:443@loadbalancer ``` -Starting from k3d v5.0.0 the example command flags `--k3s-server-arg` and `'--disable=traefik'` would have to be changed to `--k3s-arg` and `'--disable=traefik@server:*'`, respectively. +!!!note +For k3d versions less than v5.0.0, the example command flags `--k3s-arg` and `'--disable=traefik@server:*'` should change to `--k3s-server-arg` and `'--disable=traefik'`, respectively. ## The development cycle @@ -303,7 +312,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): @@ -335,7 +344,7 @@ The next thing is to make sure that unit tests are running correctly on your sys ### Run end-to-end tests -The final step is running the End-to-End testsuite, which makes sure that your Kubernetes dependencies are working properly. This will involve starting all of the Argo CD components locally on your computer. The end-to-end tests consists of two parts: a server component, and a client component. +The final step is running the End-to-End testsuite, which makes sure that your Kubernetes dependencies are working properly. This will involve starting all the Argo CD components locally on your computer. The end-to-end tests consists of two parts: a server component, and a client component. * First, start the End-to-End server: `make start-e2e-local`. This will spawn a number of processes and services on your system. * When all components have started, run `make test-e2e-local` to run the end-to-end tests against your local services. diff --git a/docs/developer-guide/ui-extensions.md b/docs/developer-guide/ui-extensions.md index 2c25748beb148..dfabfb5574ead 100644 --- a/docs/developer-guide/ui-extensions.md +++ b/docs/developer-guide/ui-extensions.md @@ -1,97 +1,2 @@ -# UI Extensions - -Argo CD web user interface can be extended with additional UI elements. Extensions should be delivered as a javascript file -in the `argocd-server` Pods that are placed in the `/tmp/extensions` directory and starts with `extension` prefix ( matches to `^extension(.*)\.js$` regex ). - -``` -/tmp/extensions -├── example1 -│   └── extension-1.js -└── example2 - └── extension-2.js -``` - -Extensions are loaded during initial page rendering and should register themselves using API exposed in the `extensionsAPI` global variable. (See -corresponding extension type details for additional information). - -The extension should provide a React component that is responsible for rendering the UI element. Extension should not bundle the React library. -Instead extension should use the `react` global variable. You can leverage `externals` setting if you are using webpack: - -```js -externals: { - react: "React"; -} -``` - -## Resource Tab Extensions - -Resource Tab extensions is an extension that provides an additional tab for the resource sliding panel at the Argo CD Application details page. - -The resource tab extension should be registered using the `extensionsAPI.registerResourceExtension` method: - -```typescript -registerResourceExtension(component: ExtensionComponent, group: string, kind: string, tabTitle: string) -``` - -- `component: ExtensionComponent` is a React component that receives the following properties: - - - application: Application - Argo CD Application resource; - - 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) - -- `group: string` - the glob expression that matches the group of the resource; note: use globstar (`**`) to match all groups including empty string; -- `kind: string` - the glob expression that matches the kind of the resource; -- `tabTitle: string` - the extension tab title. -- `opts: Object` - additional options: - - `icon: string` - the class name the represents the icon from the [https://fontawesome.com/](https://fontawesome.com/) library (e.g. 'fa-calendar-alt'); - -Below is an example of a resource tab extension: - -```javascript -((window) => { - const component = () => { - return React.createElement("div", {}, "Hello World"); - }; - window.extensionsAPI.registerResourceExtension( - component, - "*", - "*", - "Nice extension" - ); -})(window); -``` - -## System Level Extensions - -Argo CD allows you to add new items to the sidebar that will be displayed as a new page with a custom component when clicked. The system level extension should be registered using the `extensionsAPI.registerSystemLevelExtension` method: - -```typescript -registerSystemLevelExtension(component: ExtensionComponent, title: string, options: {icon?: string}) -``` - -Below is an example of a simple system level extension: - -```typescript -((window) => { - const component = () => { - return React.createElement( - "div", - { style: { padding: "10px" } }, - "Hello World" - ); - }; - window.extensionsAPI.registerSystemLevelExtension( - component, - "Test Ext", - "/hello", - "fa-flask" - ); -})(window); -``` - -## Application Tab Extensions - -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. +The contents of this document have been moved to the +[extensions guide](./extensions/ui-extensions.md) diff --git a/docs/developer-guide/use-gitpod.md b/docs/developer-guide/use-gitpod.md index bbea575b5ac5b..12b2c49eabf40 100644 --- a/docs/developer-guide/use-gitpod.md +++ b/docs/developer-guide/use-gitpod.md @@ -9,7 +9,7 @@ for Argo CD development. 1. Fork [https://github.com/argoproj/argo-cd](https://github.com/argoproj/argo-cd) repository 1. Create Gitpod workspace by opening the following url in the browser: `https://gitpod.io/#https://github.com//argo-cd` where - `` is your Github username. + `` is your GitHub username. 1. Once workspace is created you should see VSCode editor in the browser as well as workspace initialization logs in the VSCode terminal. The initialization process downloads all backend and UI dependencies as well diff --git a/docs/faq.md b/docs/faq.md index 91ba8064c4ab8..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. @@ -122,27 +131,27 @@ To terminate the sync, click on the "synchronisation" then "terminate": ![Synchronization](assets/synchronization-button.png) ![Terminate](assets/terminate-button.png) -## Why Is My App Out Of Sync Even After Syncing? +## Why Is My App `Out Of Sync` Even After Syncing? -Is some cases, the tool you use may conflict with Argo CD by adding the `app.kubernetes.io/instance` label. E.g. using +In some cases, the tool you use may conflict with Argo CD by adding the `app.kubernetes.io/instance` label. E.g. using Kustomize common labels feature. Argo CD automatically sets the `app.kubernetes.io/instance` label and uses it to determine which resources form the app. 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, ArgoCD 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? +## Why Are My Resource Limits `Out Of Sync`? Kubernetes has normalized your resource limits when they are applied, and then Argo CD has then compared the version in your generated manifests to the normalized one is Kubernetes - they won't match. @@ -157,7 +166,7 @@ E.g. To fix this use diffing customizations [settings](./user-guide/diffing.md#known-kubernetes-types-in-crds-resource-limits-volume-mounts-etc). -## How Do I Fix "invalid cookie, longer than max length 4093"? +## How Do I Fix `invalid cookie, longer than max length 4093`? Argo CD uses a JWT as the auth token. You likely are part of many groups and have gone over the 4KB limit which is set for cookies. You can get the list of groups by opening "developer tools -> network" @@ -194,7 +203,7 @@ argocd ... --insecure ## I have configured Dex via `dex.config` in `argocd-cm`, it still says Dex is unconfigured. Why? -Most likely you forgot to set the `url` in `argocd-cm` to point to your ArgoCD as well. See also +Most likely you forgot to set the `url` in `argocd-cm` to point to your Argo CD as well. See also [the docs](./operator-manual/user-management/index.md#2-configure-argo-cd-for-sso). ## Why are `SealedSecret` resources reporting a `Status`? @@ -208,14 +217,14 @@ fixed CRD if you want this feature to work at all. ## Why are resources of type `SealedSecret` stuck in the `Progressing` state? The controller of the `SealedSecret` resource may expose the status condition on resource it provisioned. Since -version `v2.0.0` ArgoCD picks up that status condition to derive a health status for the `SealedSecret`. +version `v2.0.0` Argo CD picks up that status condition to derive a health status for the `SealedSecret`. Versions before `v0.15.0` of the `SealedSecret` controller are affected by an issue regarding this status conditions updates, which is why this feature is disabled by default in these versions. Status condition updates may be enabled by starting the `SealedSecret` controller with the `--update-status` command line parameter or by setting the `SEALED_SECRETS_UPDATE_STATUS` environment variable. -To disable ArgoCD from checking the status condition on `SealedSecret` resources, add the following resource +To disable Argo CD from checking the status condition on `SealedSecret` resources, add the following resource customization in your `argocd-cm` ConfigMap via `resource.customizations.health.` key. ```yaml @@ -224,4 +233,38 @@ resource.customizations.health.bitnami.com_SealedSecret: | hs.status = "Healthy" hs.message = "Controller doesn't report resource status" return hs -``` \ No newline at end of file +``` + +## How do I fix `The order in patch list … doesn't match $setElementOrder list: …`? + +An application may trigger a sync error labeled a `ComparisonError` with a message like: + +> The order in patch list: [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]] doesn't match $setElementOrder list: [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**]] + + +There are two parts to the message: + +1. `The order in patch list: [` + + This identifies values for items, especially items that appear multiple times: + + > 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 + + `]` + +2. `doesn't match $setElementOrder list: [` + + 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. + +The most common instance of this error is with `env:` fields for `containers`. + +!!! note "Dynamic applications" + It's possible that your application is being generated by a tool in which case the duplication might not be evident within the scope of a single file. If you have trouble debugging this problem, consider filing a ticket to the owner of the generator tool asking them to improve its validation and error reporting. diff --git a/docs/getting_started.md b/docs/getting_started.md index f931bb49494fa..68d9f8f9e8872 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: @@ -36,6 +32,12 @@ Do one of: * Configure the client OS to trust the self signed certificate. * Use the --insecure flag on all Argo CD CLI operations in this guide. +!!! note + Default namespace for `kubectl` config must be set to `argocd`. + This is only needed for the following commands since the previous commands have -n argocd already: + `kubectl config set-context --current --namespace=argocd` + + Use `argocd login --core` to [configure](./user-guide/commands/argocd_login.md) CLI access and skip steps 3-5. ## 2. Download Argo CD CLI @@ -81,7 +83,7 @@ in your Argo CD installation namespace. You can simply retrieve this password using the `argocd` CLI: ```bash -argocd admin initial-password +argocd admin initial-password -n argocd ``` !!! warning diff --git a/docs/index.md b/docs/index.md index 975b4ae56cae4..ddb17c2bdc36a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,7 +25,7 @@ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/st ``` Follow our [getting started guide](getting_started.md). Further user oriented [documentation](user-guide/) -is provided for additional features. If you are looking to upgrade ArgoCD, see the [upgrade guide](./operator-manual/upgrading/overview.md). +is provided for additional features. If you are looking to upgrade Argo CD, see the [upgrade guide](./operator-manual/upgrading/overview.md). Developer oriented [documentation](developer-guide/) is available for people interested in building third-party integrations. ## How it works @@ -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 1471aa0d221cb..5f4a76d610afd 100644 --- a/docs/operator-manual/app-any-namespace.md +++ b/docs/operator-manual/app-any-namespace.md @@ -1,7 +1,5 @@ # Applications in any namespace -**Current feature state**: Beta - !!! warning Please read this documentation carefully before you enable this feature. Misconfiguration could lead to potential security issues. @@ -15,16 +13,19 @@ 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 -This feature can only be enabled and used when your Argo CD is installed as a cluster-wide instance, so it has permissions to list and manipulate resources on a cluster scope. It will *not* work with an Argo CD installed in namespace-scoped mode. +This feature can only be enabled and used when your Argo CD is installed as a cluster-wide instance, so it has permissions to list and manipulate resources on a cluster scope. It will not work with an Argo CD installed in namespace-scoped mode. ### Switch resource tracking method -Also, while technically not necessary, it is strongly suggested that you switch the application tracking method from the default `label` setting to either `annotation` or `annotation+label`. The reasonsing for this is, that application names will be a composite of the namespace's name and the name of the `Application`, and this can easily exceed the 63 characters length limit imposed on label values. Annotations have a notably greater length limit. +Also, while technically not necessary, it is strongly suggested that you switch the application tracking method from the default `label` setting to either `annotation` or `annotation+label`. The reasoning for this is, that application names will be a composite of the namespace's name and the name of the `Application`, and this can easily exceed the 63 characters length limit imposed on label values. Annotations have a notably greater length limit. To enable annotation based resource tracking, refer to the documentation about [resource tracking methods](../../user-guide/resource_tracking/) @@ -68,9 +69,11 @@ We decided to not extend the Kubernetes RBAC for the `argocd-server` workload by We supply a `ClusterRole` and `ClusterRoleBinding` suitable for this purpose in the `examples/k8s-rbac/argocd-server-applications` directory. For a default Argo CD installation (i.e. installed to the `argocd` namespace), you can just apply them as-is: ```shell -kubectl apply -f examples/k8s-rbac/argocd-server-applications/ +kubectl apply -k examples/k8s-rbac/argocd-server-applications/ ``` +`argocd-notifications-controller-rbac-clusterrole.yaml` and `argocd-notifications-controller-rbac-clusterrolebinding.yaml` are used to support notifications controller to notify apps in all namespaces. + !!! note At some later point in time, we may make this cluster role part of the default installation manifests. @@ -130,7 +133,7 @@ For backwards compatibility, if the namespace of the Application is the control ### Application RBAC -The RBAC syntax for Application objects has been changed from `/` to `//` to accomodate the need to restrict access based on the source namespace of the Application to be managed. +The RBAC syntax for Application objects has been changed from `/` to `//` to accommodate the need to restrict access based on the source namespace of the Application to be managed. For backwards compatibility, Applications in the `argocd` namespace can still be refered to as `/` in the RBAC policy rules. diff --git a/docs/operator-manual/application.yaml b/docs/operator-manual/application.yaml index c693a581a45ec..864a293ce6890 100644 --- a/docs/operator-manual/application.yaml +++ b/docs/operator-manual/application.yaml @@ -6,7 +6,10 @@ metadata: namespace: argocd # Add this finalizer ONLY if you want these to cascade delete. finalizers: + # The default behaviour is foreground cascading deletion - resources-finalizer.argocd.argoproj.io + # Alternatively, you can use background cascading deletion + # - resources-finalizer.argocd.argoproj.io/background # Add labels to your application object. labels: name: guestbook @@ -48,7 +51,7 @@ spec: # Ignore locally missing valueFiles when installing Helm chart. Defaults to false ignoreMissingValueFiles: false - # Values file as block file + # Values file as block file. Prefer to use valuesObject if possible (see below) values: | ingress: enabled: true @@ -64,6 +67,22 @@ spec: hosts: - mydomain.example.com + # Values file as block file. This takes precedence over values + valuesObject: + ingress: + enabled: true + path: / + hosts: + - mydomain.example.com + annotations: + kubernetes.io/ingress.class: nginx + kubernetes.io/tls-acme: "true" + labels: {} + tls: + - secretName: mydomain-tls + hosts: + - mydomain.example.com + # Skip custom resource definition installation if chart contains custom resource definitions. Defaults to false skipCrds: false @@ -81,10 +100,16 @@ spec: commonLabels: foo: bar commonAnnotations: - beep: boop + beep: boop-${ARGOCD_APP_REVISION} + # Toggle which enables/disables env variables substitution in commonAnnotations + commonAnnotationsEnvsubst: true images: - gcr.io/heptio-images/ks-guestbook-demo:0.2 - my-app=gcr.io/my-repo/my-app:0.1 + namespace: custom-namespace + replicas: + - name: kustomize-guestbook-ui + count: 4 # directory directory: @@ -94,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" @@ -114,9 +139,7 @@ spec: # plugin specific config plugin: - # NOTE: this field is deprecated in v2.5 and must be removed to use sidecar-based plugins. - # Only set the plugin name if the plugin is defined in argocd-cm. - # If the plugin is defined as a sidecar, omit the name. The plugin will be automatically matched with the + # If the plugin is defined as a sidecar and name is not passed, the plugin will be automatically matched with the # Application according to the plugin's discovery rules. name: mypluginname # environment variables passed to the plugin @@ -142,10 +165,18 @@ spec: # Destination cluster and namespace to deploy the application destination: + # cluster API URL server: https://kubernetes.default.svc + # or cluster name + # name: in-cluster # The namespace will only be set for namespace-scoped resources that have not set a value for .metadata.namespace namespace: guestbook - + + # Extra information to show in the Argo CD Application details tab + info: + - name: 'Example:' + value: 'https://example.com' + # Sync policy syncPolicy: automated: # automated sync by default retries failed attempts 5 times with following delays between attempts ( 5s, 10s, 20s, 40s, 80s ); retry controlled using `retry` field. @@ -157,6 +188,8 @@ spec: - CreateNamespace=true # Namespace Auto-Creation ensures that namespace specified as the application destination exists in the destination cluster. - 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 @@ -175,18 +208,24 @@ spec: maxDuration: 3m # the maximum amount of time allowed for the backoff strategy # Will ignore differences between live and desired states during the diff. Note that these configurations are not - # used during the sync process. + # used during the sync process unless the `RespectIgnoreDifferences=true` sync option is enabled. ignoreDifferences: # for the specified json pointers - group: apps kind: Deployment jsonPointers: - /spec/replicas + - kind: ConfigMap + jqPathExpressions: + - '.data["config.yaml"].auth' # for the specified managedFields managers - group: "*" kind: "*" managedFieldsManagers: - kube-controller-manager + # Name and namespace are optional. If specified, they must match exactly, these are not glob patterns. + name: my-deployment + namespace: my-namespace # RevisionHistoryLimit limits the number of items kept in the application's revision history, which is used for # informational purposes as well as for rollbacks to previous versions. This should only be changed in exceptional diff --git a/docs/operator-manual/applicationset.yaml b/docs/operator-manual/applicationset.yaml index 2267343a7c489..88264493e248d 100644 --- a/docs/operator-manual/applicationset.yaml +++ b/docs/operator-manual/applicationset.yaml @@ -3,23 +3,312 @@ kind: ApplicationSet metadata: name: test-hello-world-appset namespace: argocd + # To preserve this annotation and label we can use the preservedFields property + preservedFields: + # This annotation and label exists only on this Application, and not in + # the parent ApplicationSet template: + # ignoreApplicationDifferences is the preferred way to accomplish this now. + annotations: + my-custom-annotation: some-value + labels: + my-custom-label: some-value + spec: - # See docs for available generators and their specs. generators: - - list: - elements: - - cluster: https://kubernetes.default.svc + + # Using a generator plugin without combining it with Matrix or Merge + # Plugins allow you to provide your own generator + - plugin: + # Specify the configMap where the plugin configuration is located. + configMapRef: + name: my-plugin + # You can pass arbitrary parameters to the plugin. `input.parameters` is a map, but values may be any type. + # These parameters will also be available on the generator's output under the `generator.input.parameters` key. + input: + parameters: + key1: "value1" + key2: "value2" + list: ["list", "of", "values"] + boolean: true + map: + key1: "value1" + key2: "value2" + key3: "value3" + # You can also attach arbitrary values to the generator's output under the `values` key. These values will be + # available in templates under the `values` key. + values: + value1: something + # When using a Plugin generator, the ApplicationSet controller polls every `requeueAfterSeconds` interval (defaulting to every 30 minutes) to detect changes. + requeueAfterSeconds: 30 + + # to automatically discover repositories within an organization + - scmProvider: + # Which protocol to clone using. + cloneProtocol: ssh + # The GitHub mode uses the GitHub API to scan an organization in either github.com or GitHub Enterprise + github: + # The GitHub organization to scan. + organization: myorg + # For GitHub Enterprise: + api: https://git.example.com/ + # If true, scan every branch of every repository. If false, scan only the default branch. Defaults to false. + allBranches: true + # Reference to a Secret containing an access token. (optional) + tokenRef: + secretName: github-token + key: token + # (optional) use a GitHub App to access the API instead of a PAT. + appSecretName: gh-app-repo-creds + #Pass additional key-value pairs via values field + values: + name: "{{organization}}-{{repository}}" + + #The GitLab mode uses the GitLab API to scan and organization in either gitlab.com or self-hosted GitLab. + gitlab: + #The Gitea mode uses the Gitea API to scan organizations in your instance + gitea: + #Use the Bitbucket Server API (1.0) to scan repos in a project. + bitbucketServer: + #Uses the Azure DevOps API to look up eligible repositories + azureDevOps: + # The Bitbucket mode uses the Bitbucket API V2 to scan a workspace in bitbucket.org + bitbucket: + #Uses AWS ResourceGroupsTagging and AWS CodeCommit APIs to scan repos across AWS accounts and regionsz + awsCodeCommit: + + #Filters allow selecting which repositories to generate for. + filters: + # Include any repository starting with "myapp" AND including a Kustomize config AND labeled with "deploy-ok" ... + - repositoryMatch: ^myapp + pathsExist: [kubernetes/kustomization.yaml] + labelMatch: deploy-ok + # ... OR include any repository starting with "otherapp" AND a Helm folder and doesn't have file disabledrepo.txt. + - repositoryMatch: ^otherapp + pathsExist: [helm] + pathsDoNotExist: [disabledrepo.txt] + # matrix 'parent' generator + - matrix: + generators: + # any of the top-level generators may be used here instead. + + # merge 'parent' generator + # Use the selector set by both child generators to combine them. + - merge: + mergeKeys: + - server + # Note that this would not work with goTemplate enabled, + # nested merge keys are not supported there. + - values.selector + generators: + - clusters: + values: + kafka: 'true' + redis: 'false' + # For clusters with a specific label, enable Kafka. + - clusters: + selector: + matchLabels: + use-kafka: 'false' + values: + kafka: 'false' + # For a specific cluster, enable Redis. + - list: + elements: + - server: https://2.4.6.8 + values.redis: 'true' + + # Determines whether go templating will be used in the `template` field below. - goTemplate: false + goTemplate: true + # Optional list of go templating options, see https://pkg.go.dev/text/template#Template.Option + # This is only relevant if `goTemplate` is true + goTemplateOptions: ["missingkey=error"] + # These fields are identical to the Application spec. + # The generator's template field takes precedence over the spec's template fields template: metadata: name: test-hello-world-app spec: project: my-project + syncPolicy: + automated: + selfHeal: true + syncOptions: + - CreateNamespace=true + # defines from which Git repository to extract the desired Application manifests + source: + - chart: '{{.chart}}' + # developers may customize app details using JSON files from above repo URL + repoURL: https://github.com/argoproj/argo-cd.git + targetRevision: HEAD + # Path within the repository where Kubernetes manifests are located + path: applicationset/examples/list-generator/guestbook/{{cluster}} + helm: + useCredentials: "{{.useCredentials}}" # This field may NOT be templated, because it is a boolean field + parameters: + - name: "image.tag" + value: "pull-{{head_sha}}" + - name: "{{.name}}" + value: "{{.value}}" + - name: throw-away + value: "{{end}}" + destination: + # Only one of name or server may be specified: if both are specified, an error is returned. + # Name of the cluster (within Argo CD) to deploy to + name: production-cluster # cluster is restricted + # API Server URL for the cluster + server: '{{.url}}' + # Target namespace in which to deploy the manifests from source + namespace: dev-team-one # namespace is restricted + # This sync policy pertains to the ApplicationSet, not to the Applications it creates. syncPolicy: - # Determines whether the controller will delete Applications when an ApplicationSet is deleted. - preserveResourcesOnDeletion: false - # Alpha feature to determine the order in which ApplicationSet applies changes. + # Prevents ApplicationSet controller from modifying or deleting Applications + applicationsSync: create-only + + # Prevents ApplicationSet controller from deleting Applications. Update is allowed + # applicationsSync: create-update + + # Prevents ApplicationSet controller from modifying Applications. Delete is allowed. + # applicationsSync: create-delete + + syncOptions: + - CreateNamespace=true + # Prevent an Application's child resources from being deleted, when the parent Application is deleted + preserveResourcesOnDeletion: true + + # which fields of the ApplicationSet should be ignored when comparing Applications. + ignoreApplicationDifferences: + - jsonPointers: + - /spec/source/targetRevision + - name: some-app + jqExpressions: + - .spec.source.helm.values + strategy: + # This field lets you define fields which should be ignored when applying Application resources. This is helpful if you + # want to use ApplicationSets to create apps, but also want to allow users to modify those apps without having their + # changes overwritten by the ApplicationSet. + # This update strategy allows you to group Applications by labels present on the generated Application resources + type: RollingSync + rollingSync: + steps: + # Application groups are selected using their labels and matchExpressions + - matchExpressions: + - key: envLabel + operator: In + values: + - env-dev + # maxUpdate: 100% # if undefined, all applications matched are updated together (default is 100%) + - matchExpressions: + - key: envLabel + operator: In + values: + - env-qa + maxUpdate: 0 # if 0, no matched applications will be synced unless they're synced manually + - matchExpressions: + - key: envLabel + operator: In + values: + - env-prod + maxUpdate: 10% # maxUpdate supports both integer and percentage string values (rounds down, but floored at 1 Application for >0%) + + ignoreApplicationDifferences: + - jsonPointers: + - /spec/source/targetRevision + - name: some-app + jqPathExpressions: + - .spec.source.helm.values + + # Cluster-decision-resource-based ApplicationSet generator + - clusterDecisionResource: + # ConfigMap with GVK information for the duck type resource + configMapRef: my-configmap + name: quak # Choose either "name" of the resource or "labelSelector" + labelSelector: + matchLabels: # OPTIONAL + duck: spotted + matchExpressions: # OPTIONAL + - key: duck + operator: In + values: + - "spotted" + - "canvasback" + # OPTIONAL: Checks for changes every 60sec (default 3min) + requeueAfterSeconds: 60 + + # The Pull Request generator uses the API of an SCMaaS provider to automatically discover open pull requests within a repository + - pullRequest: + # When using a Pull Request generator, the ApplicationSet controller polls every `requeueAfterSeconds` interval (defaulting to every 30 minutes) to detect changes. + requeueAfterSeconds: 1800 + # See below for provider specific options. + # Specify the repository from which to fetch the GitHub Pull requests. + github: + # The GitHub organization or user. + owner: myorg + # The Github repository + repo: myrepository + # For GitHub Enterprise (optional) + api: https://git.example.com/ + # Reference to a Secret containing an access token. (optional) + tokenRef: + secretName: github-token + key: token + # (optional) use a GitHub App to access the API instead of a PAT. + appSecretName: github-app-repo-creds + # Labels is used to filter the PRs that you want to target. (optional) + labels: + - preview + + # Filters allow selecting which pull requests to generate for + # Include any pull request ending with "argocd". (optional) + filters: + - branchMatch: ".*-argocd" + + # Specify the project from which to fetch the GitLab merge requests. + gitlab: + # Specify the repository from which to fetch the Gitea Pull requests. + gitea: + # Fetch pull requests from a repo hosted on a Bitbucket Server (not the same as Bitbucket Cloud). + bitbucketServer: + # Fetch pull requests from a repo hosted on a Bitbucket Cloud. + bitbucket: + # Specify the organization, project and repository from which you want to fetch pull requests. + azuredevops: + # Fetch pull requests from AWS CodeCommit repositories. + awsCodeCommit: + +# The list generator generates a set of two application which then filter by the key value to only select the env with value staging + - list: + elements: + - cluster: engineering-dev + url: https://kubernetes.default.svc + env: staging + - cluster: engineering-prod + url: https://kubernetes.default.svc + env: prod + # The generator's template field takes precedence over the spec's template fields + template: + metadata: {} + spec: + project: "default" + source: + revision: HEAD + repoURL: https://github.com/argoproj/argo-cd.git + # New path value is generated here: + path: 'applicationset/examples/template-override/{{cluster}}-override' + destination: {} + + selector: + matchLabels: + env: staging + # It is also possible to use matchExpressions for more powerful selectors + - clusters: {} + selector: + matchExpressions: + - key: server + operator: In + values: + - https://kubernetes.default.svc + - https://some-other-cluster \ No newline at end of file diff --git a/docs/operator-manual/applicationset/Appset-Any-Namespace.md b/docs/operator-manual/applicationset/Appset-Any-Namespace.md new file mode 100644 index 0000000000000..4e28bc3a8172d --- /dev/null +++ b/docs/operator-manual/applicationset/Appset-Any-Namespace.md @@ -0,0 +1,231 @@ +# ApplicationSet in any namespace + +**Current feature state**: Beta + +!!! warning + Please read this documentation carefully before you enable this feature. Misconfiguration could lead to potential security issues. + +## Introduction + +As of version 2.8, Argo CD supports managing `ApplicationSet` resources in namespaces other than the control plane's namespace (which is usually `argocd`), but this feature has to be explicitly enabled and configured appropriately. + +Argo CD administrators can define a certain set of namespaces where `ApplicationSet` resources may be created, updated and reconciled in. + +As Applications generated by an ApplicationSet are generated in the same namespace as the ApplicationSet itself, this works in combination with [App in any namespace](../app-any-namespace.md). + +## Prerequisites + +### App in any namespace configured + +This feature needs [App in any namespace](../app-any-namespace.md) feature activated. The list of namespaces must be the same. + +### Cluster-scoped Argo CD installation + +This feature can only be enabled and used when your Argo CD ApplicationSet controller is installed as a cluster-wide instance, so it has permissions to list and manipulate resources on a cluster scope. It will *not* work with an Argo CD installed in namespace-scoped mode. + +### SCM Providers secrets consideration + +By allowing ApplicationSet in any namespace you must be aware that any secrets can be exfiltrated using `scmProvider` or `pullRequest` generators. + +Here is an example: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: myapps +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + - scmProvider: + gitea: + # The Gitea owner to scan. + owner: myorg + # With this malicious setting, user can send all request to a Pod that will log incoming requests including headers with tokens + api: http://my-service.my-namespace.svc.cluster.local + # If true, scan every branch of every repository. If false, scan only the default branch. Defaults to false. + allBranches: true + # By changing this token reference, user can exfiltrate any secrets + tokenRef: + secretName: gitea-token + key: token + template: +``` + +Therefore administrator must restrict the urls of the allowed SCM Providers (example: `https://git.mydomain.com/,https://gitlab.mydomain.com/`) by setting the environment variable `ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS` to argocd-cmd-params-cm `applicationsetcontroller.allowed.scm.providers`. If another url is used, it will be rejected by the applicationset controller. + +For example: +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cmd-params-cm +data: + applicationsetcontroller.allowed.scm.providers: https://git.mydomain.com/,https://gitlab.mydomain.com/ +``` + +!!! note + Please note url used in the `api` field of the `ApplicationSet` must match the url declared by the Administrator including the protocol + +!!! warning + The allow-list only applies to SCM providers for which the user may configure a custom `api`. Where an SCM or PR + generator does not accept a custom API URL, the provider is implicitly allowed. + +If you do not intend to allow users to use the SCM or PR generators, you can disable them entirely by setting the environment variable `ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS` to argocd-cmd-params-cm `applicationsetcontroller.enable.scm.providers` to `false`. + +### Overview + +In order for an ApplicationSet to be managed and reconciled outside the Argo CD's control plane namespace, two prerequisites must match: + +1. The namespace list from which `argocd-applicationset-controller` can source `ApplicationSets` must be explicitly set using environment variable `ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES` or alternatively using parameter `--applicationset-namespaces`. +2. The enabled namespaces must be entirely covered by the [App in any namespace](../app-any-namespace.md), otherwise the generated Applications generated outside the allowed Application namespaces won't be reconciled + +It can be achieved by setting the environment variable `ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES` to argocd-cmd-params-cm `applicationsetcontroller.namespaces` + +`ApplicationSets` in different namespaces can be created and managed just like any other `ApplicationSet` in the `argocd` namespace previously, either declaratively or through the Argo CD API (e.g. using the CLI, the web UI, the REST API, etc). + +### Reconfigure Argo CD to allow certain namespaces + +#### Change workload startup parameters + +In order to enable this feature, the Argo CD administrator must reconfigure the and `argocd-applicationset-controller` workloads to add the `--applicationset-namespaces` parameter to the container's startup command. + +### Safely template project + +As [App in any namespace](../app-any-namespace.md) is a prerequisite, it is possible to safely template project. + +Let's take an example with two teams and an infra project: + +```yaml +kind: AppProject +apiVersion: argoproj.io/v1alpha1 +metadata: + name: infra-project + namespace: argocd +spec: + destinations: + - namespace: '*' +``` + +```yaml +kind: AppProject +apiVersion: argoproj.io/v1alpha1 +metadata: + name: team-one-project + namespace: argocd +spec: + sourceNamespaces: + - team-one-cd +``` + +```yaml +kind: AppProject +apiVersion: argoproj.io/v1alpha1 +metadata: + name: team-two-project + namespace: argocd +spec: + sourceNamespaces: + - team-two-cd +``` + +Creating following `ApplicationSet` generates two Applications `infra-escalation` and `team-two-escalation`. Both will be rejected as they are outside `argocd` namespace, therefore `sourceNamespaces` will be checked + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: team-one-product-one + namespace: team-one-cd +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + list: + - name: infra + project: infra-project + - name: team-two + project: team-two-project + template: + metadata: + name: '{{.name}}-escalation' + spec: + project: "{{.project}}" +``` + +### ApplicationSet names + +For the CLI, applicationSets are now referred to and displayed as in the format `/`. + +For backwards compatibility, if the namespace of the ApplicationSet is the control plane's namespace (i.e. `argocd`), the `` can be omitted from the applicationset name when referring to it. For example, the application names `argocd/someappset` and `someappset` are semantically the same and refer to the same application in the CLI and the UI. + +### Applicationsets RBAC + +The RBAC syntax for Application objects has been changed from `/` to `//` to accommodate the need to restrict access based on the source namespace of the Application to be managed. + +For backwards compatibility, Applications in the argocd namespace can still be referred to as `/` in the RBAC policy rules. + +Wildcards do not make any distinction between project and applicationset namespaces yet. For example, the following RBAC rule would match any application belonging to project foo, regardless of the namespace it is created in: + + +``` +p, somerole, applicationsets, get, foo/*, allow +``` + +If you want to restrict access to be granted only to `ApplicationSets` with project `foo` within namespace `bar`, the rule would need to be adapted as follows: + +``` +p, somerole, applicationsets, get, foo/bar/*, allow +``` + +## Managing applicationSets in other namespaces + +### Using the CLI + +You can use all existing Argo CD CLI commands for managing applications in other namespaces, exactly as you would use the CLI to manage applications in the control plane's namespace. + +For example, to retrieve the `ApplicationSet` named `foo` in the namespace `bar`, you can use the following CLI command: + +```shell +argocd appset get foo/bar +``` + +Likewise, to manage this applicationSet, keep referring to it as `foo/bar`: + +```bash +# Delete the application +argocd appset delete foo/bar +``` + +There is no change on the create command as it is using a file. You just need to add the namespace in the `metadata.namespace` field. + +As stated previously, for applicationSets in the Argo CD's control plane namespace, you can omit the namespace from the application name. + +### Using the REST API + +If you are using the REST API, the namespace for `ApplicationSet` cannot be specified as the application name, and resources need to be specified using the optional `appNamespace` query parameter. For example, to work with the `ApplicationSet` resource named `foo` in the namespace `bar`, the request would look like follows: + +```bash +GET /api/v1/applicationsets/foo?appsetNamespace=bar +``` + +For other operations such as `POST` and `PUT`, the `appNamespace` parameter must be part of the request's payload. + +For `ApplicationSet` resources in the control plane namespace, this parameter can be omitted. + +## Clusters secrets consideration + +By allowing ApplicationSet in any namespace you must be aware that clusters can be discovered and used. + +Example: + +Following will discover all clusters + +```yaml +spec: + generators: + - clusters: {} # Automatically use all clusters defined within Argo CD +``` + +If you don't want to allow users to discover all clusters with ApplicationSets from other namespaces you may consider deploying ArgoCD in namespace scope or use OPA rules. \ No newline at end of file diff --git a/docs/operator-manual/applicationset/Controlling-Resource-Modification.md b/docs/operator-manual/applicationset/Controlling-Resource-Modification.md index f0bf6d37693ba..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,18 +14,50 @@ 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. -### Policy - `create-only`: Prevent ApplicationSet controller from modifying or deleting Applications +## 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. -The `--policy` parameter takes one of the following valid values: `sync`, `create-only`, `create-update`, and `create-delete`. (`sync` is the default, which is used if the `--policy` parameter is not specified; the other policies are described below). +The `--policy` parameter takes four values: `sync`, `create-only`, `create-delete`, and `create-update`. (`sync` is the default, which is used if the `--policy` parameter is not specified; the other policies are described below). + +It is also possible to set this policy per ApplicationSet. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +spec: + # (...) + syncPolicy: + applicationsSync: create-only # create-update, create-delete sync + +``` + +- 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`). + +### 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: ``` --policy create-only ``` -### Policy - `create-update`: Prevent ApplicationSet controller from deleting Applications +At ApplicationSet level + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +spec: + # (...) + syncPolicy: + applicationsSync: create-only +``` + +## 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`: ``` @@ -34,14 +66,124 @@ To allow the ApplicationSet controller to create or modify `Application` resourc This may be useful to users looking for additional protection against deletion of the Applications generated by the controller. -### Policy - `create-delete`: Prevent ApplicationSet controller from updating Applications +At ApplicationSet level + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +spec: + # (...) + syncPolicy: + applicationsSync: create-update +``` + +## 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. + +The field supports multiple ignore rules. Each ignore rule may specify a list of either `jsonPointers` or +`jqPathExpressions` to ignore. + +You may optionally also specify a `name` to apply the ignore rule to a specific Application, or omit the `name` to apply +the ignore rule to all Applications. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +spec: + ignoreApplicationDifferences: + - jsonPointers: + - /spec/source/targetRevision + - name: some-app + jqPathExpressions: + - .spec.source.helm.values +``` + +### 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. -To allow the ApplicationSet controller to create or delete `Application` resources, but prevent Applications from being updated, add the following parameter to the ApplicationSet controller `Deployment`: +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 ``` ---policy create-delete + +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 ``` -### Prevent an `Application`'s child resources from being deleted, when the parent Application is deleted +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). @@ -57,7 +199,8 @@ 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)). @@ -121,52 +264,60 @@ cd applicationset/manifests kubectl apply -n argocd -f install.yaml ``` -## Limitations: what isn't supported as of the current release - -Here is a list of commonly requested resource modification features which are not supported as of the current release. This lack of support is *not* necessarily by design; rather these behaviours are documented here to provide clear, concise descriptions of the current state of the feature. - -### Limitation: Control resource modification on a per ApplicationSet basis - -There is currently no way to restrict modification/deletion of the Applications that are owned by an *individual* ApplicationSet. The global `--policy` parameters described above only allow targeting of *all* ApplicationSets (eg it is 'all or nothing'). - -### Limitation: No support for manual edits to individual Applications - -There is currently no way to allow modification of a single child Application of an ApplicationSet, for example, if you wanted to make manual edits to a single Application for debugging/testing purposes. - -For example: - -- Imagine that you have an ApplicationSet that created Applications `app1`, `app2`, and `app3`. -- You now want to edit `app3` with `kubectl edit application/app3`, to update one of the `app3`'s fields. -- However, as soon as you make edits to `app3` (or any of the individual Applications), they will be immediately reverted by the ApplicationSet reconciler back to the `template`-ized version (by design). - -As of this writing, there is [an issue open](https://github.com/argoproj/applicationset/issues/186) for discussion of this behaviour. +## 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`. -### Limitation: ApplicationSet controller will not selectively ignore changes to individual fields +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. -There is currently no way to instruct the ApplicationSet controller to ignore changes to individual fields of Applications. - -For example, imagine that we have an Application created from an ApplicationSet, but a user has attempted to add a custom annotation (to the Application) that does not exist in the `ApplicationSet` resource: +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: ```yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: + # This annotation and label exists only on this Application, and not in + # the parent ApplicationSet template: annotations: - # This annotation exists only on this Application, and not in - # the parent ApplicationSet template: my-custom-annotation: some-value + labels: + my-custom-label: some-value spec: # (...) ``` -As above, the `ApplicationSet` resource does not have a `my-custom-annotation: some-value` annotation in the `.spec.template.annotations` for the Application. +To preserve this annotation and label we can use the `preservedFields` property of the `ApplicationSet` like so: +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +spec: + # (...) + preservedFields: + annotations: ["my-custom-annotation"] + labels: ["my-custom-label"] +``` + +The ApplicationSet controller will leave this annotation and label as-is when reconciling, even though it is not defined in the metadata of the ApplicationSet itself. -Since this field is not in the ApplicationSet template, as soon as a user adds this custom annotation, it will be immediately reverted (removed) by the ApplicationSet controller. +By default, the Argo CD notifications and the Argo CD refresh type annotations are also preserved. -There is currently no support for disabling or customizing this behaviour. +!!!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. -To some extent this is by design: the main principle of ApplicationSets is that we maintain a 1-to-many relationship between the ApplicationSet and the Applications that it owns, such that all the Applications necessarily conform to a strict template. +## Debugging unexpected changes to Applications -This provides the advantages of the 'cattle not pets' philosophy of microservice/cloud native application resource management, wherein you don't need to worry about individual Applications differing from each other in subtle ways: they will all necessarily be reconciled to be consistent with the parent template. +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: -BUT, admittedly, that is not always desirable 100% of the time, and there may be a better balance to be found, so discussions are continuing on GitHub and Slack. +```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 26a457e5de408..aa18983fe3d54 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,11 +69,19 @@ metadata: name: guestbook namespace: argocd spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - clusters: selector: matchLabels: staging: true + # The cluster generator also supports matchExpressions. + #matchExpressions: + # - key: staging + # operator: In + # values: + # - "true" template: # (...) ``` @@ -99,11 +109,19 @@ 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: matchLabels: argocd.argoproj.io/secret-type: cluster + # The cluster generator also supports matchExpressions. + #matchExpressions: + # - key: staging + # operator: In + # values: + # - "true" ``` This selector will not match the default local cluster, since the default local cluster does not have a Secret (and thus does not have the `argocd.argoproj.io/secret-type` label on that secret). Any cluster selector that selects on that label will automatically exclude the default local cluster. @@ -118,6 +136,29 @@ However, if you do wish to target both local and non-local clusters, while also These steps might seem counterintuitive, but the act of changing one of the default values for the local cluster causes the Argo CD Web UI to create a new secret for this cluster. In the Argo CD namespace, you should now see a Secret resource named `cluster-(cluster suffix)` with label `argocd.argoproj.io/secret-type": "cluster"`. You may also create a local [cluster secret declaratively](../../declarative-setup/#clusters), or with the CLI using `argocd cluster add "(context name)" --in-cluster`, rather than through the Web UI. +### Fetch clusters based on their K8s version + +There is also the possibility to fetch clusters based upon their Kubernetes version. To do this, the label `argocd.argoproj.io/auto-label-cluster-info` needs to be set to `true` on the cluster secret. +Once that has been set, the controller will dynamically label the cluster secret with the Kubernetes version it is running on. To retrieve that value, you need to use the +`argocd.argoproj.io/kubernetes-version`, as the example below demonstrates: + +```yaml +spec: + goTemplate: true + generators: + - clusters: + selector: + matchLabels: + argocd.argoproj.io/kubernetes-version: 1.28 + # matchExpressions are also supported. + #matchExpressions: + # - key: argocd.argoproj.io/kubernetes-version + # operator: In + # values: + # - "1.27" + # - "1.28" +``` + ### Pass additional key-value pairs via `values` field You may pass additional, arbitrary string key-value pairs via the `values` field of the cluster generator. Values added via the `values` field are added as `values.(field)` @@ -125,6 +166,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: @@ -142,16 +185,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 ``` @@ -172,6 +215,8 @@ Extending the example above, we could do something like this: ```yaml spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - clusters: selector: @@ -180,8 +225,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: @@ -189,19 +234,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-File-Globbing.md b/docs/operator-manual/applicationset/Generators-Git-File-Globbing.md new file mode 100644 index 0000000000000..4f8967b5937fa --- /dev/null +++ b/docs/operator-manual/applicationset/Generators-Git-File-Globbing.md @@ -0,0 +1,85 @@ +# Git File Generator Globbing + +## Problem Statement + +The original and default implementation of the Git file generator does very greedy globbing. This can trigger errors or catch users off-guard. For example, consider the following repository layout: + +``` +└── cluster-charts/ + ├── cluster1 + │ ├── mychart/ + │ │  ├── charts/ + │ │   │   └── mysubchart/ + │ │ │ ├── values.yaml + │ │   │   └── etc… + │ │   ├── values.yaml + │ │ └── etc… + │ └── myotherchart/ + │ ├── values.yaml + │ └── etc… + └── cluster2 + └── etc… +``` + +In `cluster1` we have two charts, one of them with a subchart. + +Assuming we need the ApplicationSet to template values in the `values.yaml`, then we need to use a Git file generator instead of a directory generator. The value of the `path` key of the Git file generator should be set to: + +``` +path: cluster-charts/*/*/values.yaml +``` + +However, the default implementation will interpret the above pattern as: + +``` +path: cluster-charts/**/values.yaml +``` + +Meaning, for `mychart` in `cluster1`, that it will pick up both the chart's `values.yaml` but also the one from its subchart. This will most likely fail, and even if it didn't it would be wrong. + +There are multiple other ways this undesirable globbing can fail. For example: + +``` +path: some-path/*.yaml +``` + +This will return all YAML files in any directory at any level under `some-path`, instead of only those directly under it. + +## Enabling the New Globbing + +Since some users may rely on the old behavior it was decided to make the fix optional and not enabled by default. + +It can be enabled in any of these ways: + +1. Pass `--enable-new-git-file-globbing` to the ApplicationSet controller args. +1. Set `ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING=true` in the ApplicationSet controller environment variables. +1. Set `applicationsetcontroller.enable.new.git.file.globbing: true` in the Argo CD ConfigMap. + +Note that the default may change in the future. + +## Usage + +The new Git file generator globbing uses the `doublestar` package. You can find it [here](https://github.com/bmatcuk/doublestar). + +Below is a short excerpt from its documentation. + +doublestar patterns match files and directories recursively. For example, if +you had the following directory structure: + +```bash +grandparent +`-- parent + |-- child1 + `-- child2 +``` + +You could find the children with patterns such as: `**/child*`, +`grandparent/**/child?`, `**/parent/*`, or even just `**` by itself (which will +return all files and directories recursively). + +Bash's globstar is doublestar's inspiration and, as such, works similarly. +Note that the doublestar must appear as a path component by itself. A pattern +such as `/path**` is invalid and will be treated the same as `/path*`, but +`/path*/**` should achieve the desired result. Additionally, `/path/**` will +match all directories and files under the path directory, but `/path/**/` will +only match directories. diff --git a/docs/operator-manual/applicationset/Generators-Git.md b/docs/operator-manual/applicationset/Generators-Git.md index e78fdf2812c6a..7e4aa5fdb1c24 100644 --- a/docs/operator-manual/applicationset/Generators-Git.md +++ b/docs/operator-manual/applicationset/Generators-Git.md @@ -37,6 +37,8 @@ metadata: name: cluster-addons namespace: argocd spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/argoproj/argo-cd.git @@ -45,16 +47,16 @@ spec: - path: applicationset/examples/git-generator-directory/cluster-addons/* template: metadata: - name: '{{path.basename}}' + name: '{{.path.basename}}' spec: project: "my-project" source: repoURL: https://github.com/argoproj/argo-cd.git targetRevision: HEAD - path: '{{path}}' + path: '{{.path.path}}' destination: server: https://kubernetes.default.svc - namespace: '{{path.basename}}' + namespace: '{{.path.basename}}' syncPolicy: syncOptions: - CreateNamespace=true @@ -63,14 +65,14 @@ spec: The generator parameters are: -- `{{path}}`: The directory paths within the Git repository that match the `path` wildcard. -- `{{path[n]}}`: The directory paths within the Git repository that match the `path` wildcard, split into array elements (`n` - array index) -- `{{path.basename}}`: For any directory path within the Git repository that matches the `path` wildcard, the right-most path name is extracted (e.g. `/directory/directory2` would produce `directory2`). -- `{{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.path}}`: The directory paths within the Git repository that match the `path` wildcard. +- `{{index .path.segments n}}`: The directory paths within the Git repository that match the `path` wildcard, split into array elements (`n` - array index) +- `{{.path.basename}}`: For any directory path within the Git repository that matches the `path` wildcard, the right-most path name is extracted (e.g. `/directory/directory2` would produce `directory2`). +- `{{.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). -**Note**: The right-most path name always becomes `{{path.basename}}`. For example, for `- path: /one/two/three/four`, `{{path.basename}}` is `four`. +**Note**: The right-most path name always becomes `{{.path.basename}}`. For example, for `- path: /one/two/three/four`, `{{.path.basename}}` is `four`. -**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). +**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). Whenever a new Helm chart/Kustomize YAML/Application/plain subdirectory is added to the Git repository, the ApplicationSet controller will detect this change and automatically deploy the resulting manifests within new `Application` resources. @@ -89,6 +91,8 @@ metadata: name: cluster-addons namespace: argocd spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/argoproj/argo-cd.git @@ -99,18 +103,18 @@ spec: exclude: true template: metadata: - name: '{{path.basename}}' + name: '{{.path.basename}}' spec: project: "my-project" source: repoURL: https://github.com/argoproj/argo-cd.git targetRevision: HEAD - path: '{{path}}' + path: '{{.path.path}}' destination: server: https://kubernetes.default.svc - namespace: '{{path.basename}}' + namespace: '{{.path.basename}}' ``` -(*The full example can be found [here](https://github.com/argoproj/argo-cd/tree/master/examples/applicationset/git-generator-directory/excludes).*) +(*The full example can be found [here](https://github.com/argoproj/argo-cd/tree/master/applicationset/examples/git-generator-directory/excludes).*) This example excludes the `exclude-helm-guestbook` directory from the list of directories scanned for this `ApplicationSet` resource. @@ -153,7 +157,7 @@ Or, a shorter way (using [path.Match](https://golang.org/pkg/path/#Match) syntax ```yaml - path: /d/* -- path: /d/[f|g] +- path: /d/[fg] exclude: true ``` @@ -170,6 +174,8 @@ metadata: name: cluster-addons namespace: argocd spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/example/example-repo.git @@ -180,18 +186,59 @@ spec: exclude: true 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}}' + destination: + server: https://kubernetes.default.svc + namespace: '{{.path.basename}}' +``` + +### Pass additional key-value pairs via `values` field + +You may pass additional, arbitrary string key-value pairs via the `values` field of the git directory generator. Values added via the `values` field are added as `values.(field)`. + +In this example, a `cluster` parameter value is passed. It is interpolated from the `branch` and `path` variable, to then be used to determine the destination namespace. +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: cluster-addons + namespace: argocd +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + - git: + repoURL: https://github.com/example/example-repo.git + revision: HEAD + directories: + - path: '*' + values: + cluster: '{{.branch}}-{{.path.basename}}' + template: + metadata: + 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: '{{path.basename}}' + namespace: '{{.values.cluster}}' ``` +!!! note + The `values.` prefix is always prepended to values provided via `generators.git.values` field. Ensure you include this prefix in the parameter name within the `template` when using it. + +In `values` we can also interpolate all fields set by the git directory generator as mentioned above. + ## Git Generator: Files The Git file generator is the second subtype of the Git generator. The Git file generator generates parameters using the contents of JSON/YAML files found within a specified repository. @@ -249,6 +296,8 @@ metadata: name: guestbook namespace: argocd spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/argoproj/argo-cd.git @@ -257,7 +306,7 @@ spec: - path: "applicationset/examples/git-generator-files-discovery/cluster-config/**/config.json" template: metadata: - name: '{{cluster.name}}-guestbook' + name: '{{.cluster.name}}-guestbook' spec: project: default source: @@ -265,29 +314,72 @@ spec: targetRevision: HEAD path: "applicationset/examples/git-generator-files-discovery/apps/guestbook" destination: - server: '{{cluster.address}}' + server: '{{.cluster.address}}' namespace: guestbook ``` (*The full example can be found [here](https://github.com/argoproj/argo-cd/tree/master/applicationset/examples/git-generator-files-discovery).*) -Any `config.json` files found under the `cluster-config` directory will be parameterized based on the `path` wildcard pattern specified. Within each file JSON fields are flattened into key/value pairs, with this ApplicationSet example using the `cluster.address` as `cluster.name` parameters in the template. +Any `config.json` files found under the `cluster-config` directory will be parameterized based on the `path` wildcard pattern specified. Within each file JSON fields are flattened into key/value pairs, with this ApplicationSet example using the `cluster.address` and `cluster.name` parameters in the template. As with other generators, clusters *must* already be defined within Argo CD, in order to generate Applications for them. 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). +**Note**: The default behavior of the Git file generator is very greedy. Please see [Git File Generator Globbing](./Generators-Git-File-Globbing.md) for more information. + +### Pass additional key-value pairs via `values` field + +You may pass additional, arbitrary string key-value pairs via the `values` field of the git files generator. Values added via the `values` field are added as `values.(field)`. + +In this example, a `base_dir` parameter value is passed. It is interpolated from `path` segments, to then be used to determine the source path. +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: guestbook + namespace: argocd +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + - git: + repoURL: https://github.com/argoproj/argo-cd.git + revision: HEAD + files: + - path: "applicationset/examples/git-generator-files-discovery/cluster-config/**/config.json" + values: + base_dir: "{{index .path 0}}/{{index .path 1}}/{{index .path 2}}" + template: + metadata: + name: '{{.cluster.name}}-guestbook' + spec: + project: default + source: + repoURL: https://github.com/argoproj/argo-cd.git + targetRevision: HEAD + path: "{{.values.base_dir}}/apps/guestbook" + destination: + server: '{{.cluster.address}}' + namespace: guestbook +``` + +!!! note + The `values.` prefix is always prepended to values provided via `generators.git.values` field. Ensure you include this prefix in the parameter name within the `template` when using it. + +In `values` we can also interpolate all fields set by the git files generator as mentioned above. + ## Webhook Configuration When using a Git generator, ApplicationSet polls Git repositories every three minutes to detect changes. To eliminate @@ -295,7 +387,7 @@ this delay from polling, the ApplicationSet webhook server can be configured to Git webhook notifications from GitHub and GitLab. The following explains how to configure a Git webhook for GitHub, but the same process should be applicable to other providers. !!! note - ApplicationSet exposes the webhook server as a service of type ClusterIP. An Ingress resource needs to be created to expose this service to the webhook source. + The ApplicationSet controller webhook does not use the same webhook as the API server as defined [here](../webhook.md). ApplicationSet exposes a webhook server as a service of type ClusterIP. An ApplicationSet specific Ingress resource needs to be created to expose this service to the webhook source. ### 1. Create the webhook in the Git provider @@ -317,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 6b99a854a0f2f..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).*) @@ -38,18 +39,78 @@ With the ApplicationSet v0.1.0 release, one could *only* specify `url` and `clus spec: generators: - list: - elements: - # v0.1.0 form - requires cluster/url keys: - - cluster: engineering-dev - url: https://kubernetes.default.svc - values: - additional: value - # v0.2.0+ form - does not require cluster/URL keys - # (but they are still supported). - - staging: "true" - gitRepo: https://kubernetes.default.svc + elements: + # v0.1.0 form - requires cluster/url keys: + - cluster: engineering-dev + url: https://kubernetes.default.svc + values: + additional: value + # v0.2.0+ form - does not require cluster/URL keys + # (but they are still supported). + - staging: "true" + gitRepo: https://kubernetes.default.svc # (...) ``` !!! note "Clusters must be predefined in Argo CD" These clusters *must* already be defined within Argo CD, in order to generate applications for these values. The ApplicationSet controller does not create clusters within Argo CD (for instance, it does not have the credentials to do so). + +## Dynamically generated elements +The List generator can also dynamically generate its elements based on a yaml/json it gets from a previous generator like git by combining the two with a matrix generator. In this example we are using the matrix generator with a git followed by a list generator and pass the content of a file in git as input to the `elementsYaml` field of the list generator: +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: elementsYaml + namespace: argocd +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + - matrix: + generators: + - git: + repoURL: https://github.com/argoproj/argo-cd.git + revision: HEAD + files: + - path: applicationset/examples/list-generator/list-elementsYaml-example.yaml + - list: + elementsYaml: "{{ .key.components | toJson }}" + template: + metadata: + name: '{{.name}}' + spec: + project: default + syncPolicy: + automated: + selfHeal: true + syncOptions: + - CreateNamespace=true + sources: + - chart: '{{.chart}}' + repoURL: '{{.repoUrl}}' + targetRevision: '{{.version}}' + helm: + releaseName: '{{.releaseName}}' + destination: + server: https://kubernetes.default.svc + namespace: '{{.namespace}}' +``` + +where `list-elementsYaml-example.yaml` content is: +```yaml +key: + components: + - name: component1 + chart: podinfo + version: "6.3.2" + releaseName: component1 + repoUrl: "https://stefanprodan.github.io/podinfo" + namespace: component1 + - name: component2 + chart: podinfo + version: "6.3.3" + releaseName: component2 + repoUrl: "ghcr.io/stefanprodan/charts" + namespace: component2 +``` diff --git a/docs/operator-manual/applicationset/Generators-Matrix.md b/docs/operator-manual/applicationset/Generators-Matrix.md index c0316d61c333c..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,12 +166,94 @@ 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`) +## Overriding parameters from one child generator in another child generator + +The Matrix Generator allows parameters with the same name to be defined in multiple child generators. This is useful, for example, to define default values for all stages in one generator and override them with stage-specific values in another generator. The example below generates a Helm-based application using a matrix generator with two git generators: the first provides stage-specific values (one directory per stage) and the second provides global values for all stages. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: parameter-override-example +spec: + generators: + - matrix: + generators: + - git: + repoURL: https://github.com/example/values.git + revision: HEAD + files: + - path: "**/stage.values.yaml" + - git: + repoURL: https://github.com/example/values.git + revision: HEAD + files: + - path: "global.values.yaml" + goTemplate: true + template: + metadata: + name: example + spec: + project: default + source: + repoURL: https://github.com/example/example-app.git + targetRevision: HEAD + path: . + helm: + values: | + {{ `{{ . | mustToPrettyJson }}` }} + destination: + server: in-cluster + namespace: default +``` + +Given the following structure/content of the example/values repository: + +``` +├── test +│ └── stage.values.yaml +│ stageName: test +│ cpuRequest: 100m +│ debugEnabled: true +├── staging +│ └── stage.values.yaml +│ stageName: staging +├── production +│ └── stage.values.yaml +│ stageName: production +│ memoryLimit: 512Mi +│ debugEnabled: false +└── global.values.yaml + cpuRequest: 200m + memoryLimit: 256Mi + debugEnabled: true +``` + +The matrix generator above would yield the following results: + +```yaml +- stageName: test + cpuRequest: 100m + memoryLimit: 256Mi + debugEnabled: true + +- stageName: staging + cpuRequest: 200m + memoryLimit: 256Mi + debugEnabled: true + +- stageName: production + cpuRequest: 200m + memoryLimit: 512Mi + debugEnabled: false +``` + ## Example: Two Git Generators Using `pathParamPrefix` The matrix generator will fail if its children produce results containing identical keys with differing values. @@ -180,6 +266,8 @@ kind: ApplicationSet metadata: name: two-gits-with-path-param-prefix spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - matrix: generators: @@ -198,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: {} # ... ``` @@ -308,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 @@ -316,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: @@ -325,10 +413,21 @@ 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. + + - matrix: + generators: + - matrix: + generators: + - list + elements: + - # (...) + selector: { } # Only applied when applyNestedSelectors is true diff --git a/docs/operator-manual/applicationset/Generators-Merge.md b/docs/operator-manual/applicationset/Generators-Merge.md index eb32343accbf4..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 ``` @@ -111,6 +113,72 @@ When merged with the updated base parameters, the `values.redis` value for the p values.redis: 'true' ``` +## Example: Use value interpolation in merge + +Some generators support additional values and interpolating from generated variables to selected values. This can be used to teach the merge generator which generated variables to use to combine different generators. + +The following example combines discovered clusters and a git repository by cluster labels and the branch name: +```yaml +apiVersion: argoproj.io/v1alpha1 +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. + - merge: + mergeKeys: + # Note that this would not work with goTemplate enabled, + # nested merge keys are not supported there. + - values.selector + generators: + # Assuming, all configured clusters have a label for their location: + # Set the selector to this location. + - clusters: + values: + selector: '{{index .metadata.labels "location"}}' + # The git repo may have different directories which correspond to the + # cluster locations, using these as a selector. + - git: + repoURL: https://github.com/argoproj/argocd-example-apps/ + revision: HEAD + directories: + - path: '*' + values: + selector: '{{.path.path}}' + template: + metadata: + name: '{{.name}}' + spec: + 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}}' + destination: + server: '{{.server}}' + namespace: default +``` + +Assuming a cluster named `germany01` with the label `metadata.labels.location=Germany` and a git repository containing a directory called `Germany`, this could combine to values as follows: + +```yaml + # From the cluster generator +- name: germany01 + server: https://1.2.3.4 + # From the git generator + path: Germany + # Combining selector with the merge generator + values.selector: 'Germany' + # More values from cluster & git generator + # […] +``` + + ## Restrictions 1. You should specify only a single generator per array entry. This is not valid: @@ -142,3 +210,23 @@ When merged with the updated base parameters, the `values.redis` value for the p - list: elements: - # (...) + +1. Merging on nested values while using `goTemplate: true` is currently not supported, this will not work + + spec: + goTemplate: true + generators: + - merge: + mergeKeys: + - values.merge + +1. When using a Merge 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`. + + - merge: + generators: + - merge: + generators: + - list + elements: + - # (...) + selector: { } # Only applied when applyNestedSelectors is true diff --git a/docs/operator-manual/applicationset/Generators-Plugin.md b/docs/operator-manual/applicationset/Generators-Plugin.md new file mode 100644 index 0000000000000..d0888b9949b8e --- /dev/null +++ b/docs/operator-manual/applicationset/Generators-Plugin.md @@ -0,0 +1,344 @@ +# Plugin Generator + +Plugins allow you to provide your own generator. + +- You can write in any language +- Simple: a plugin just responds to RPC HTTP requests. +- You can use it in a sidecar, or standalone deployment. +- You can get your plugin running today, no need to wait 3-5 months for review, approval, merge and an Argo software + release. +- You can combine it with Matrix or Merge. + +To start working on your own plugin, you can generate a new repository based on the example +[applicationset-hello-plugin](https://github.com/argoproj-labs/applicationset-hello-plugin). + +## Simple example + +Using a generator plugin without combining it with Matrix or Merge. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: myplugin +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + - plugin: + # Specify the configMap where the plugin configuration is located. + configMapRef: + name: my-plugin + # You can pass arbitrary parameters to the plugin. `input.parameters` is a map, but values may be any type. + # These parameters will also be available on the generator's output under the `generator.input.parameters` key. + input: + parameters: + key1: "value1" + key2: "value2" + list: ["list", "of", "values"] + boolean: true + map: + key1: "value1" + key2: "value2" + key3: "value3" + + # You can also attach arbitrary values to the generator's output under the `values` key. These values will be + # available in templates under the `values` key. + values: + value1: something + + # When using a Plugin generator, the ApplicationSet controller polls every `requeueAfterSeconds` interval (defaulting to every 30 minutes) to detect changes. + requeueAfterSeconds: 30 + template: + metadata: + name: myplugin + annotations: + 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 }}" +``` + +- `configMapRef.name`: A `ConfigMap` name containing the plugin configuration to use for RPC call. +- `input.parameters`: Input parameters included in the RPC call to the plugin. (Optional) + +!!! note + The concept of the plugin should not undermine the spirit of GitOps by externalizing data outside of Git. The goal is to be complementary in specific contexts. + For example, when using one of the PullRequest generators, it's impossible to retrieve parameters related to the CI (only the commit hash is available), which limits the possibilities. By using a plugin, it's possible to retrieve the necessary parameters from a separate data source and use them to extend the functionality of the generator. + +### Add a ConfigMap to configure the access of the plugin + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: my-plugin + namespace: argocd +data: + token: "$plugin.myplugin.token" # Alternatively $:plugin.myplugin.token + baseUrl: "http://myplugin.plugin-ns.svc.cluster.local." +``` + +- `token`: Pre-shared token used to authenticate HTTP request (points to the right key you created in the `argocd-secret` Secret) +- `baseUrl`: BaseUrl of the k8s service exposing your plugin in the cluster. + +### Store credentials + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: argocd-secret + namespace: argocd + labels: + app.kubernetes.io/name: argocd-secret + app.kubernetes.io/part-of: argocd +type: Opaque +data: + # ... + # The secret value must be base64 encoded **once**. + # this value corresponds to: `printf "strong-password" | base64`. + plugin.myplugin.token: "c3Ryb25nLXBhc3N3b3Jk" + # ... +``` + +#### Alternative + +If you want to store sensitive data in **another** Kubernetes `Secret`, instead of `argocd-secret`, ArgoCD knows how to check the keys under `data` in your Kubernetes `Secret` for a corresponding key whenever a value in a configmap starts with `$`, then your Kubernetes `Secret` name and `:` (colon) followed by the key name. + +Syntax: `$:` + +> NOTE: Secret must have label `app.kubernetes.io/part-of: argocd` + +##### Example + +`another-secret`: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: another-secret + namespace: argocd + labels: + app.kubernetes.io/part-of: argocd +type: Opaque +data: + # ... + # Store client secret like below. + # The secret value must be base64 encoded **once**. + # This value corresponds to: `printf "strong-password" | base64`. + plugin.myplugin.token: "c3Ryb25nLXBhc3N3b3Jk" +``` + +### HTTP server + +#### A Simple Python Plugin + +You can deploy it either as a sidecar or as a standalone deployment (the latter is recommended). + +In the example, the token is stored in a file at this location : `/var/run/argo/token` + +``` +strong-password +``` + +```python +import json +from http.server import BaseHTTPRequestHandler, HTTPServer + +with open("/var/run/argo/token") as f: + plugin_token = f.read().strip() + + +class Plugin(BaseHTTPRequestHandler): + + def args(self): + return json.loads(self.rfile.read(int(self.headers.get('Content-Length')))) + + def reply(self, reply): + self.send_response(200) + self.end_headers() + self.wfile.write(json.dumps(reply).encode("UTF-8")) + + def forbidden(self): + self.send_response(403) + self.end_headers() + + def unsupported(self): + self.send_response(404) + self.end_headers() + + def do_POST(self): + if self.headers.get("Authorization") != "Bearer " + plugin_token: + self.forbidden() + + if self.path == '/api/v1/getparams.execute': + args = self.args() + self.reply({ + "output": { + "parameters": [ + { + "key1": "val1", + "key2": "val2" + }, + { + "key1": "val2", + "key2": "val2" + } + ] + } + }) + else: + self.unsupported() + + +if __name__ == '__main__': + httpd = HTTPServer(('', 4355), Plugin) + httpd.serve_forever() +``` + +Execute getparams with curl : + +``` +curl http://localhost:4355/api/v1/getparams.execute -H "Authorization: Bearer strong-password" -d \ +'{ + "applicationSetName": "fake-appset", + "input": { + "parameters": { + "param1": "value1" + } + } +}' +``` + +Some things to note here: + +- You only need to implement the calls `/api/v1/getparams.execute` +- You should check that the `Authorization` header contains the same bearer value as `/var/run/argo/token`. Return 403 if not +- The input parameters are included in the request body and can be accessed using the `input.parameters` variable. +- The output must always be a list of object maps nested under the `output.parameters` key in a map. +- `generator.input.parameters` and `values` are reserved keys. If present in the plugin output, these keys will be overwritten by the + contents of the `input.parameters` and `values` keys in the ApplicationSet's plugin generator spec. + +## With matrix and pull request example + +In the following example, the plugin implementation is returning a set of image digests for the given branch. The returned list contains only one item corresponding to the latest built image for the branch. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: fb-matrix +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + - matrix: + generators: + - pullRequest: + github: ... + requeueAfterSeconds: 30 + - plugin: + configMapRef: + name: cm-plugin + input: + parameters: + branch: "{{.branch}}" # provided by generator pull request + values: + branchLink: "https://git.example.com/org/repo/tree/{{.branch}}" + template: + metadata: + name: "fb-matrix-{{.branch}}" + spec: + source: + repoURL: "https://github.com/myorg/myrepo.git" + targetRevision: "HEAD" + path: charts/my-chart + helm: + releaseName: fb-matrix-{{.branch}} + valueFiles: + - values.yaml + values: | + front: + image: myregistry:{{.branch}}@{{ .digestFront }} # digestFront is generated by the plugin + back: + image: myregistry:{{.branch}}@{{ .digestBack }} # digestBack is generated by the plugin + project: default + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true + destination: + server: https://kubernetes.default.svc + namespace: "{{.branch}}" + info: + - name: Link to the Application's branch + value: "{{values.branchLink}}" +``` + +To illustrate : + +- The generator pullRequest would return, for example, 2 branches: `feature-branch-1` and `feature-branch-2`. + +- The generator plugin would then perform 2 requests as follows : + +```shell +curl http://localhost:4355/api/v1/getparams.execute -H "Authorization: Bearer strong-password" -d \ +'{ + "applicationSetName": "fb-matrix", + "input": { + "parameters": { + "branch": "feature-branch-1" + } + } +}' +``` + +Then, + +```shell +curl http://localhost:4355/api/v1/getparams.execute -H "Authorization: Bearer strong-password" -d \ +'{ + "applicationSetName": "fb-matrix", + "input": { + "parameters": { + "branch": "feature-branch-2" + } + } +}' +``` + +For each call, it would return a unique result such as : + +```json +{ + "output": { + "parameters": [ + { + "digestFront": "sha256:a3f18c17771cc1051b790b453a0217b585723b37f14b413ad7c5b12d4534d411", + "digestBack": "sha256:4411417d614d5b1b479933b7420079671facd434fd42db196dc1f4cc55ba13ce" + } + ] + } +} +``` + +Then, + +```json +{ + "output": { + "parameters": [ + { + "digestFront": "sha256:7c20b927946805124f67a0cb8848a8fb1344d16b4d0425d63aaa3f2427c20497", + "digestBack": "sha256:e55e7e40700bbab9e542aba56c593cb87d680cefdfba3dd2ab9cfcb27ec384c2" + } + ] + } +} +``` + +In this example, by combining the two, you ensure that one or more pull requests are available and that the generated tag has been properly generated. This wouldn't have been possible with just a commit hash because a hash alone does not certify the success of the build. diff --git a/docs/operator-manual/applicationset/Generators-Post-Selector.md b/docs/operator-manual/applicationset/Generators-Post-Selector.md new file mode 100644 index 0000000000000..896e89e267d7c --- /dev/null +++ b/docs/operator-manual/applicationset/Generators-Post-Selector.md @@ -0,0 +1,61 @@ +# 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`: + +## Example: List generator + Post Selector +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: guestbook +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + - list: + elements: + - cluster: engineering-dev + url: https://kubernetes.default.svc + env: staging + - cluster: engineering-prod + url: https://kubernetes.default.svc + env: prod + selector: + matchLabels: + env: staging + template: + metadata: + name: '{{.cluster}}-guestbook' + spec: + project: default + source: + repoURL: https://github.com/argoproj-labs/applicationset.git + targetRevision: HEAD + path: examples/list-generator/guestbook/{{.cluster}} + destination: + server: '{{.url}}' + namespace: guestbook +``` + +The List generator + Post Selector generates a single set of parameters: + +```yaml +- cluster: engineering-dev + url: https://kubernetes.default.svc + env: staging +``` + +It is also possible to use `matchExpressions` for more powerful selectors. + +```yaml +spec: + generators: + - clusters: {} + selector: + matchExpressions: + - key: server + operator: In + values: + - https://kubernetes.default.svc + - https://some-other-cluster +``` diff --git a/docs/operator-manual/applicationset/Generators-Pull-Request.md b/docs/operator-manual/applicationset/Generators-Pull-Request.md index d90eb2d0f4695..a213c1dbb23bb 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,11 +79,13 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: gitlab: - # The GitLab project. - project: myproject + # The GitLab project ID. + project: "12341234" # For self-hosted GitLab (optional) api: https://git.example.com/ # Reference to a Secret containing an access token. (optional) @@ -91,16 +97,21 @@ spec: - preview # MR state is used to filter MRs only with a certain state. (optional) pullRequestState: opened + # If true, skips validating the SCM provider's TLS certificate - useful for self-signed certificates. + insecure: false requeueAfterSeconds: 1800 template: # ... ``` -* `project`: Required name of the GitLab project. +* `project`: Required project ID of the GitLab project. * `api`: If using self-hosted GitLab, the URL to access it. (Optional) * `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. (Optional) * `labels`: Labels is used to filter the MRs that you want to target. (Optional) * `pullRequestState`: PullRequestState is an additional MRs filter to get only those with a certain state. Default: "" (all states) +* `insecure`: By default (false) - Skip checking the validity of the SCM's certificate - useful for self-signed TLS certificates. + +As a preferable alternative to setting `insecure` to true, you can configure self-signed TLS certificates for Gitlab by [mounting self-signed certificate to the applicationset controller](./Generators-SCM-Provider.md#self-signed-tls-certificates). ## Gitea @@ -112,6 +123,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: gitea: @@ -148,6 +161,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: bitbucketServer: @@ -180,6 +195,106 @@ If you want to access a private repository, you must also provide the credential * `username`: The username to authenticate with. It only needs read access to the relevant repo. * `passwordRef`: A `Secret` name and key containing the password or personal access token to use for requests. +## Bitbucket Cloud + +Fetch pull requests from a repo hosted on a Bitbucket Cloud. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: myapps +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + - pullRequest: + bitbucket: + # Workspace name where the repoistory is stored under. Required. + owner: myproject + # Repository slug. Required. + repo: myrepository + # URL of the Bitbucket Server. (optional) Will default to 'https://api.bitbucket.org/2.0'. + api: https://api.bitbucket.org/2.0 + # Credentials for Basic authentication (App Password). Either basicAuth or bearerToken + # authentication is required to access private repositories + basicAuth: + # The username to authenticate with + username: myuser + # Reference to a Secret containing the password or personal access token. + passwordRef: + secretName: mypassword + key: password + # Credentials for Bearer Token (App Token) authentication. Either basicAuth or bearerToken + # authentication is required to access private repositories + bearerToken: + tokenRef: + secretName: repotoken + key: token + # Labels are not supported by Bitbucket Cloud, so filtering by label is not possible. + # Filter PRs using the source branch name. (optional) + filters: + - branchMatch: ".*-argocd" + template: + # ... +``` + +- `owner`: Required name of the Bitbucket workspace +- `repo`: Required name of the Bitbucket repository. +- `api`: Optional URL to access the Bitbucket REST API. For the example above, an API request would be made to `https://api.bitbucket.org/2.0/repositories/{workspace}/{repo_slug}/pullrequests`. If not set, defaults to `https://api.bitbucket.org/2.0` +- `branchMatch`: Optional regexp filter which should match the source branch name. This is an alternative to labels which are not supported by Bitbucket server. + +If you want to access a private repository, Argo CD will need credentials to access repository in Bitbucket Cloud. You can use Bitbucket App Password (generated per user, with access to whole workspace), or Bitbucket App Token (generated per repository, with access limited to repository scope only). If both App Password and App Token are defined, App Token will be used. + +To use Bitbucket App Password, use `basicAuth` section. +- `username`: The username to authenticate with. It only needs read access to the relevant repo. +- `passwordRef`: A `Secret` name and key containing the password or personal access token to use for requests. + +In case of Bitbucket App Token, go with `bearerToken` section. +- `tokenRef`: A `Secret` name and key containing the app token to use for requests. + +## Azure DevOps + +Specify the organization, project and repository from which you want to fetch pull requests. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: myapps +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + - pullRequest: + azuredevops: + # Azure DevOps org to scan. Required. + organization: myorg + # Azure DevOps project name to scan. Required. + project: myproject + # Azure DevOps repo name to scan. Required. + repo: myrepository + # The Azure DevOps API URL to talk to. If blank, use https://dev.azure.com/. + api: https://dev.azure.com/ + # Reference to a Secret containing an access token. (optional) + tokenRef: + secretName: azure-devops-token + key: token + # Labels is used to filter the PRs that you want to target. (optional) + labels: + - preview + requeueAfterSeconds: 1800 + template: + # ... +``` + +* `organization`: Required name of the Azure DevOps organization. +* `project`: Required name of the Azure DevOps project. +* `repo`: Required name of the Azure DevOps repository. +* `api`: If using self-hosted Azure DevOps Repos, the URL to access it. (Optional) +* `tokenRef`: A `Secret` name and key containing the Azure DevOps 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. (Optional) +* `labels`: Filter the PRs to those containing **all** of the labels listed. (Optional) + ## Filters Filters allow selecting which pull requests to generate for. Each filter can declare one or more conditions, all of which must pass. If multiple filters are present, any can match for a repository to be included. If no filters are specified, all pull requests will be processed. @@ -191,6 +306,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: # ... @@ -202,6 +319,7 @@ spec: ``` * `branchMatch`: A regexp matched against source branch names. +* `targetBranchMatch`: A regexp matched against target branch names. [GitHub](#github) and [GitLab](#gitlab) also support a `labels` filter. @@ -217,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 @@ -246,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 @@ -272,8 +394,11 @@ spec: * `number`: The ID number of the pull request. * `branch`: The name of the branch of the pull request head. * `branch_slug`: The branch name will be cleaned to be conform to the DNS label standard as defined in [RFC 1123](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names), and truncated to 50 characters to give room to append/suffix-ing it with 13 more characters. +* `target_branch`: The name of the target branch of the pull request. +* `target_branch_slug`: The target branch name will be cleaned to be conform to the DNS label standard as defined in [RFC 1123](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-label-names), and truncated to 50 characters to give room to append/suffix-ing it with 13 more characters. * `head_sha`: This is the SHA of the head of the pull request. * `head_short_sha`: This is the short SHA of the head of the pull request (8 characters long or the length of the head SHA if it's shorter). +* `head_short_sha_7`: This is the short SHA of the head of the pull request (7 characters long or the length of the head SHA if it's shorter). * `labels`: The array of pull request labels. (Supported only for Go Template ApplicationSet manifests.) ## Webhook Configuration @@ -282,6 +407,9 @@ When using a Pull Request generator, the ApplicationSet controller polls every ` The configuration is almost the same as the one described [in the Git generator](Generators-Git.md), but there is one difference: if you want to use the Pull Request Generator as well, additionally configure the following settings. +!!! note + The ApplicationSet controller webhook does not use the same webhook as the API server as defined [here](../webhook.md). ApplicationSet exposes a webhook server as a service of type ClusterIP. An ApplicationSet specific Ingress resource needs to be created to expose this service to the webhook source. + ### Github webhook configuration In section 1, _"Create the webhook in the Git provider"_, add an event so that a webhook request will be sent when a pull request is created, closed, or label changed. diff --git a/docs/operator-manual/applicationset/Generators-SCM-Provider.md b/docs/operator-manual/applicationset/Generators-SCM-Provider.md index e8f8cfe5abbcc..40c8e552fe573 100644 --- a/docs/operator-manual/applicationset/Generators-SCM-Provider.md +++ b/docs/operator-manual/applicationset/Generators-SCM-Provider.md @@ -87,10 +87,17 @@ spec: allBranches: true # If true, recurses through subgroups. If false, it searches only in the base group. Defaults to false. includeSubgroups: true + # If true and includeSubgroups is also true, include Shared Projects, which is gitlab API default. + # If false only search Projects under the same path. Defaults to true. + includeSharedProjects: false + # filter projects by topic. A single topic is supported by Gitlab API. Defaults to "" (all topics). + topic: "my-topic" # Reference to a Secret containing an access token. (optional) tokenRef: secretName: gitlab-token key: token + # If true, skips validating the SCM provider's TLS certificate - useful for self-signed certificates. + insecure: false template: # ... ``` @@ -99,12 +106,23 @@ spec: * `api`: If using self-hosted GitLab, the URL to access it. * `allBranches`: By default (false) the template will only be evaluated for the default branch of each repo. If this is true, every branch of every repository will be passed to the filters. If using this flag, you likely want to use a `branchMatch` filter. * `includeSubgroups`: By default (false) the controller will only search for repos directly in the base group. If this is true, it will recurse through all the subgroups searching for repos to scan. +* `includeSharedProjects`: If true and includeSubgroups is also true, include Shared Projects, which is gitlab API default. If false only search Projects under the same path. In general most would want the behaviour when set to false. Defaults to true. +* `topic`: filter projects by topic. A single topic is supported by Gitlab API. Defaults to "" (all topics). * `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`. +### Self-signed TLS Certificates + +As a preferable alternative to setting `insecure` to true, you can configure self-signed TLS certificates for Gitlab. + +In order for a self-signed TLS certificate be used by an ApplicationSet's SCM / PR Gitlab Generator, the certificate needs to be mounted on the applicationset-controller. The path of the mounted certificate must be explicitly set using the environment variable `ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH` or alternatively using parameter `--scm-root-ca-path`. The applicationset controller will read the mounted certificate to create the Gitlab client for SCM/PR Providers + +This can be achieved conveniently by setting `applicationsetcontroller.scm.root.ca.path` in the argocd-cmd-params-cm ConfigMap. Be sure to restart the ApplicationSet controller after setting this value. + ## Gitea The Gitea mode uses the Gitea API to scan organizations in your instance @@ -255,6 +273,87 @@ This SCM provider does not yet support label filtering Available clone protocols are `ssh` and `https`. +## AWS CodeCommit (Alpha) + +Uses AWS ResourceGroupsTagging and AWS CodeCommit APIs to scan repos across AWS accounts and regions. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: myapps +spec: + generators: + - scmProvider: + awsCodeCommit: + # AWS region to scan repos. + # default to the environmental region from ApplicationSet controller. + region: us-east-1 + # AWS role to assume to scan repos. + # default to the environmental role from ApplicationSet controller. + role: arn:aws:iam::111111111111:role/argocd-application-set-discovery + # If true, scan every branch of every repository. If false, scan only the main branch. Defaults to false. + allBranches: true + # AWS resource tags to filter repos with. + # see https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/API_GetResources.html#resourcegrouptagging-GetResources-request-TagFilters for details + # default to no tagFilters, to include all repos in the region. + tagFilters: + - key: organization + value: platform-engineering + - key: argo-ready + template: + # ... +``` + +* `region`: (Optional) AWS region to scan repos. By default, use ApplicationSet controller's current region. +* `role`: (Optional) AWS role to assume to scan repos. By default, use ApplicationSet controller's current role. +* `allBranches`: (Optional) If `true`, scans every branch of eligible repositories. If `false`, check only the default branch of the eligible repositories. Default `false`. +* `tagFilters`: (Optional) A list of tagFilters to filter AWS CodeCommit repos with. See [AWS ResourceGroupsTagging API](https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/API_GetResources.html#resourcegrouptagging-GetResources-request-TagFilters) for details. By default, no filter is included. + +This SCM provider does not support the following features + +* label filtering +* `sha`, `short_sha` and `short_sha_7` template parameters + +Available clone protocols are `ssh`, `https` and `https-fips`. + +### AWS IAM Permission Considerations + +In order to call AWS APIs to discover AWS CodeCommit repos, ApplicationSet controller must be configured with valid environmental AWS config, like current AWS region and AWS credentials. +AWS config can be provided via all standard options, like Instance Metadata Service (IMDS), config file, environment variables, or IAM roles for service accounts (IRSA). + +Depending on whether `role` is provided in `awsCodeCommit` property, AWS IAM permission requirement is different. + +#### Discover AWS CodeCommit Repositories in the same AWS Account as ApplicationSet Controller + +Without specifying `role`, ApplicationSet controller will use its own AWS identity to scan AWS CodeCommit repos. +This is suitable when you have a simple setup that all AWS CodeCommit repos reside in the same AWS account as your Argo CD. + +As the ApplicationSet controller AWS identity is used directly for repo discovery, it must be granted below AWS permissions. + +* `tag:GetResources` +* `codecommit:ListRepositories` +* `codecommit:GetRepository` +* `codecommit:GetFolder` +* `codecommit:ListBranches` + +#### Discover AWS CodeCommit Repositories across AWS Accounts and Regions + +By specifying `role`, ApplicationSet controller will first assume the `role`, and use it for repo discovery. +This enables more complicated use cases to discover repos from different AWS accounts and regions. + +The ApplicationSet controller AWS identity should be granted permission to assume target AWS roles. + +* `sts:AssumeRole` + +All AWS roles must have repo discovery related permissions. + +* `tag:GetResources` +* `codecommit:ListRepositories` +* `codecommit:GetRepository` +* `codecommit:GetFolder` +* `codecommit:ListBranches` + ## Filters Filters allow selecting which repositories to generate for. Each filter can declare one or more conditions, all of which must pass. If multiple filters are present, any can match for a repository to be included. If no filters are specified, all repositories will be processed. @@ -296,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: @@ -319,5 +420,52 @@ spec: * `branch`: The default branch of the repository. * `sha`: The Git commit SHA for the branch. * `short_sha`: The abbreviated Git commit SHA for the branch (8 chars or the length of the `sha` if it's shorter). -* `labels`: A comma-separated list of repository labels. +* `short_sha_7`: The abbreviated Git commit SHA for the branch (7 chars or the length of the `sha` if it's shorter). +* `labels`: A comma-separated list of repository labels in case of Gitea, repository topics in case of Gitlab and Github. Not supported by Bitbucket Cloud, Bitbucket Server, or Azure DevOps. * `branchNormalized`: The value of `branch` normalized to contain only lowercase alphanumeric characters, '-' or '.'. + +## Pass additional key-value pairs via `values` field + +You may pass additional, arbitrary string key-value pairs via the `values` field of any SCM generator. Values added via the `values` field are added as `values.(field)`. + +In this example, a `name` parameter value is passed. It is interpolated from `organization` and `repository` to generate a different template name. +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: myapps +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + - scmProvider: + bitbucketServer: + project: myproject + api: https://mycompany.bitbucket.org + allBranches: true + basicAuth: + username: myuser + passwordRef: + secretName: mypassword + key: password + values: + name: "{{.organization}}-{{.repository}}" + + template: + metadata: + name: '{{ .values.name }}' + spec: + source: + repoURL: '{{ .url }}' + targetRevision: '{{ .branch }}' + path: kubernetes/ + project: default + destination: + server: https://kubernetes.default.svc + namespace: default +``` + +!!! note + The `values.` prefix is always prepended to values provided via `generators.scmProvider.values` field. Ensure you include this prefix in the parameter name within the `template` when using it. + +In `values` we can also interpolate all fields set by the SCM generator as mentioned above. diff --git a/docs/operator-manual/applicationset/Generators.md b/docs/operator-manual/applicationset/Generators.md index cd61db5da7918..78600c771fddd 100644 --- a/docs/operator-manual/applicationset/Generators.md +++ b/docs/operator-manual/applicationset/Generators.md @@ -4,9 +4,9 @@ Generators are responsible for generating *parameters*, which are then rendered Generators are primarily based on the data source that they use to generate the template parameters. For example: the List generator provides a set of parameters from a *literal list*, the Cluster generator uses the *Argo CD cluster list* as a source, the Git generator uses files/directories from a *Git repository*, and so. -As of this writing there are eight generators: +As of this writing there are nine generators: -- [List generator](Generators-List.md): The List generator allows you to target Argo CD Applications to clusters based on a fixed list of cluster name/URL values. +- [List generator](Generators-List.md): The List generator allows you to target Argo CD Applications to clusters based on a fixed list of any chosen key/value element pairs. - [Cluster generator](Generators-Cluster.md): The Cluster generator allows you to target Argo CD Applications to clusters, based on the list of clusters defined within (and managed by) Argo CD (which includes automatically responding to cluster addition/removal events from Argo CD). - [Git generator](Generators-Git.md): The Git generator allows you to create Applications based on files within a Git repository, or based on the directory structure of a Git repository. - [Matrix generator](Generators-Matrix.md): The Matrix generator may be used to combine the generated parameters of two separate generators. @@ -14,5 +14,8 @@ As of this writing there are eight generators: - [SCM Provider generator](Generators-SCM-Provider.md): The SCM Provider generator uses the API of an SCM provider (eg GitHub) to automatically discover repositories within an organization. - [Pull Request generator](Generators-Pull-Request.md): The Pull Request generator uses the API of an SCMaaS provider (eg GitHub) to automatically discover open pull requests within an repository. - [Cluster Decision Resource generator](Generators-Cluster-Decision-Resource.md): The Cluster Decision Resource generator is used to interface with Kubernetes custom resources that use custom resource-specific logic to decide which set of Argo CD clusters to deploy to. +- [Plugin generator](Generators-Plugin.md): The Plugin generator make RPC HTTP request to provide parameters. + +All generators can be filtered by using the [Post Selector](Generators-Post-Selector.md) If you are new to generators, begin with the **List** and **Cluster** generators. For more advanced use cases, see the documentation for the remaining generators above. diff --git a/docs/operator-manual/applicationset/GoTemplate.md b/docs/operator-manual/applicationset/GoTemplate.md index 911754009ab14..1b651200bc6cc 100644 --- a/docs/operator-manual/applicationset/GoTemplate.md +++ b/docs/operator-manual/applicationset/GoTemplate.md @@ -12,6 +12,38 @@ 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`. + +The recommended setting of `goTemplateOptions` is `["missingkey=error"]`, which ensures that if undefined values are +looked up by your template then an error is reported instead of being ignored silently. This is not currently the default +behavior, for backwards compatibility. + ## Motivation Go Template is the Go Standard for string templating. It is also more powerful than fasttemplate (the default templating @@ -29,6 +61,7 @@ possible with Go text templates: kind: ApplicationSet spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] template: spec: source: @@ -42,6 +75,7 @@ possible with Go text templates: kind: ApplicationSet spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] template: spec: syncPolicy: "{{.syncPolicy}}" # This field may NOT be templated, because it is an object field. @@ -53,6 +87,7 @@ possible with Go text templates: kind: ApplicationSet spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] template: spec: source: @@ -87,7 +122,12 @@ By activating Go Templating, `{{ .path }}` becomes an object. Therefore, some ch generators' templating: - `{{ path }}` becomes `{{ .path.path }}` +- `{{ path.basename }}` becomes `{{ .path.basename }}` +- `{{ path.basenameNormalized }}` becomes `{{ .path.basenameNormalized }}` +- `{{ path.filename }}` becomes `{{ .path.filename }}` +- `{{ path.filenameNormalized }}` becomes `{{ .path.filenameNormalized }}` - `{{ path[n] }}` becomes `{{ index .path.segments n }}` +- `{{ values }}` if being used in the file generator becomes `{{ .values }}` Here is an example: @@ -126,6 +166,7 @@ metadata: name: cluster-addons spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/argoproj/argo-cd.git @@ -157,6 +198,20 @@ It is also possible to use Sprig functions to construct the path variables manua | `{{path.filenameNormalized}}` | `{{.path.filenameNormalized}}` | `{{normalize .path.filename}}` | | `{{path[N]}}` | `-` | `{{index .path.segments N}}` | +## Available template functions + +ApplicationSet controller provides: + +- all [sprig](http://masterminds.github.io/sprig/) Go templates function except `env`, `expandenv` and `getHostByName` +- `normalize`: sanitizes the input so that it complies with the following rules: + 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 + + ## Examples ### Basic Go template usage @@ -170,6 +225,7 @@ metadata: name: guestbook spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - list: elements: @@ -205,6 +261,7 @@ metadata: name: guestbook spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - list: elements: @@ -215,7 +272,7 @@ spec: nameSuffix: -my-name-suffix template: metadata: - name: '{{.cluster}}{{default "" .nameSuffix}}' + name: '{{.cluster}}{{dig "nameSuffix" "" .}}' spec: project: default source: @@ -229,3 +286,7 @@ spec: This ApplicationSet will produce an Application called `engineering-dev` and another called `engineering-prod-my-name-suffix`. + +Note that unset parameters are an error, so you need to avoid looking up a property that doesn't exist. Instead, use +template functions like `dig` to do the lookup with a default. If you prefer to have unset parameters default to zero, +you can remove `goTemplateOptions: ["missingkey=error"]` or set it to `goTemplateOptions: ["missingkey=invalid"]` diff --git a/docs/operator-manual/applicationset/Progressive-Rollouts.md b/docs/operator-manual/applicationset/Progressive-Syncs.md similarity index 78% rename from docs/operator-manual/applicationset/Progressive-Rollouts.md rename to docs/operator-manual/applicationset/Progressive-Syncs.md index aa7d01702102f..edfe0dad101f2 100644 --- a/docs/operator-manual/applicationset/Progressive-Rollouts.md +++ b/docs/operator-manual/applicationset/Progressive-Syncs.md @@ -1,21 +1,21 @@ -# Progressive Rollouts +# Progressive Syncs !!! warning "Alpha Feature" This is an experimental, alpha-quality feature that allows you to control the order in which the ApplicationSet controller will create or update the Applications owned by an ApplicationSet resource. It may be removed in future releases or modified in backwards-incompatible ways. ## Use Cases -The Progressive Rollouts feature set is intended to be light and flexible. The feature only interacts with the health of managed Applications. It is not intended to support direct integrations with other Rollout controllers (such as the native ReplicaSet controller or Argo Rollouts). +The Progressive Syncs feature set is intended to be light and flexible. The feature only interacts with the health of managed Applications. It is not intended to support direct integrations with other Rollout controllers (such as the native ReplicaSet controller or Argo Rollouts). -* Progressive Rollouts watch for the managed Application resources to become "Healthy" before proceeding to the next stage. +* Progressive Syncs watch for the managed Application resources to become "Healthy" before proceeding to the next stage. * Deployments, DaemonSets, StatefulSets, and [Argo Rollouts](https://argoproj.github.io/argo-rollouts/) are all supported, because the Application enters a "Progressing" state while pods are being rolled out. In fact, any resource with a health check that can report a "Progressing" status is supported. * [Argo CD Resource Hooks](../../user-guide/resource_hooks.md) are supported. We recommend this approach for users that need advanced functionality when an Argo Rollout cannot be used, such as smoke testing after a DaemonSet change. -## Enabling Progressive Rollouts -As an experimental feature, progressive rollouts must be explicitly enabled, in one of these ways. +## Enabling Progressive Syncs +As an experimental feature, progressive syncs must be explicitly enabled, in one of these ways. -1. Pass `--enable-progressive-rollouts` to the ApplicationSet controller args. -1. Set `ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS=true` in the ApplicationSet controller environment variables. -1. Set `applicationsetcontroller.enable.progressive.rollouts: true` in the ArgoCD ConfigMap. +1. Pass `--enable-progressive-syncs` to the ApplicationSet controller args. +1. Set `ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS=true` in the ApplicationSet controller environment variables. +1. Set `applicationsetcontroller.enable.progressive.syncs: true` in the Argo CD `argocd-cmd-params-cm` ConfigMap. ## Strategies @@ -31,10 +31,10 @@ All Applications managed by the ApplicationSet resource are updated simultaneous This update strategy allows you to group Applications by labels present on the generated Application resources. When the ApplicationSet changes, the changes will be applied to each group of Application resources sequentially. -* Application groups are selected by `matchExpressions`. +* Application groups are selected using their labels and `matchExpressions`. * All `matchExpressions` must be true for an Application to be selected (multiple expressions match with AND behavior). * The `In` and `NotIn` operators must match at least one value to be considered true (OR behavior). -* The `NotIn` operatorn has priority in the event that both a `NotIn` and `In` operator produce a match. +* The `NotIn` operator has priority in the event that both a `NotIn` and `In` operator produce a match. * All Applications in each group must become Healthy before the ApplicationSet controller will proceed to update the next group of Applications. * The number of simultaneous Application updates in a group will not exceed its `maxUpdate` parameter (default is 100%, unbounded). * RollingSync will capture external changes outside the ApplicationSet resource, since it relies on watching the OutOfSync status of the managed Applications. @@ -44,7 +44,7 @@ When the ApplicationSet changes, the changes will be applied to each group of Ap * If an Application is considered "Pending" for `applicationsetcontroller.default.application.progressing.timeout` seconds, the Application is automatically moved to Healthy status (default 300). #### Example -The following example illustrates how to stage a progressive rollout over Applications with explicitly configured environment labels. +The following example illustrates how to stage a progressive sync over Applications with explicitly configured environment labels. Once a change is pushed, the following will happen in order. @@ -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: @@ -76,29 +75,30 @@ spec: rollingSync: steps: - matchExpressions: - - key: env + - key: envLabel operator: In values: - env-dev #maxUpdate: 100% # if undefined, all applications matched are updated together (default is 100%) - matchExpressions: - - key: env + - key: envLabel operator: In values: - env-qa maxUpdate: 0 # if 0, no matched applications will be updated - matchExpressions: - - key: env + - key: envLabel operator: In values: - env-prod maxUpdate: 10% # maxUpdate supports both integer and percentage string values (rounds down, but floored at 1 Application for >0%) goTemplate: true + goTemplateOptions: ["missingkey=error"] template: metadata: name: '{{.cluster}}-guestbook' labels: - env: '{{.env}}' + envLabel: '{{.env}}' spec: project: my-project source: diff --git a/docs/operator-manual/applicationset/Template.md b/docs/operator-manual/applicationset/Template.md index f66a403586bbd..d96fb39252fed 100644 --- a/docs/operator-manual/applicationset/Template.md +++ b/docs/operator-manual/applicationset/Template.md @@ -85,7 +85,7 @@ spec: spec: project: "default" source: - revision: HEAD + targetRevision: HEAD repoURL: https://github.com/argoproj/argo-cd.git # New path value is generated here: path: 'applicationset/examples/template-override/{{cluster}}-override' @@ -99,7 +99,7 @@ spec: source: repoURL: https://github.com/argoproj/argo-cd.git targetRevision: HEAD - # This 'default' value is not used: it is is replaced by the generator's template path, above + # This 'default' value is not used: it is replaced by the generator's template path, above path: applicationset/examples/template-override/default destination: server: '{{url}}' @@ -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/applicationset-specification.md b/docs/operator-manual/applicationset/applicationset-specification.md new file mode 100644 index 0000000000000..8899057bf7ff6 --- /dev/null +++ b/docs/operator-manual/applicationset/applicationset-specification.md @@ -0,0 +1,7 @@ +# ApplicationSet Specification + +The following describes all the available fields of an ApplicationSet: + +```yaml +{!docs/operator-manual/applicationset.yaml!} +``` 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.md b/docs/operator-manual/argocd-cm-yaml.md new file mode 100644 index 0000000000000..666e78d03fc1b --- /dev/null +++ b/docs/operator-manual/argocd-cm-yaml.md @@ -0,0 +1,7 @@ +# argocd-cm.yaml example + +An example of an argocd-cm.yaml file: + +```yaml +{!docs/operator-manual/argocd-cm.yaml!} +``` diff --git a/docs/operator-manual/argocd-cm.yaml b/docs/operator-manual/argocd-cm.yaml index 6618b567beac6..49458d40be929 100644 --- a/docs/operator-manual/argocd-cm.yaml +++ b/docs/operator-manual/argocd-cm.yaml @@ -85,6 +85,7 @@ data: # Configuration to customize resource behavior (optional) can be configured via splitted sub keys. # Keys are in the form: resource.customizations.ignoreDifferences., resource.customizations.health. # resource.customizations.actions., resource.customizations.knownTypeFields. + # resource.customizations.ignoreResourceUpdates. resource.customizations.ignoreDifferences.admissionregistration.k8s.io_MutatingWebhookConfiguration: | jsonPointers: - /webhooks/0/clientConfig/caBundle @@ -101,6 +102,33 @@ data: jsonPointers: - /spec/replicas + # Enable resource.customizations.ignoreResourceUpdates rules. If "false," those rules are not applied, and all updates + # to resources are applied to the cluster cache. Default is false. + resource.ignoreResourceUpdatesEnabled: "false" + + # Configuration to define customizations ignoring differences during watched resource updates to skip application reconciles. + resource.customizations.ignoreResourceUpdates.all: | + jsonPointers: + - /metadata/resourceVersion + + # Configuration to define customizations ignoring differences during watched resource updates can be configured via splitted sub key. + resource.customizations.ignoreResourceUpdates.argoproj.io_Application: | + jsonPointers: + - /status + + # jsonPointers and jqPathExpressions can be specified. + resource.customizations.ignoreResourceUpdates.autoscaling_HorizontalPodAutoscaler: | + jqPathExpressions: + - '.metadata.annotations."autoscaling.alpha.kubernetes.io/behavior"' + - '.metadata.annotations."autoscaling.alpha.kubernetes.io/conditions"' + - '.metadata.annotations."autoscaling.alpha.kubernetes.io/metrics"' + - '.metadata.annotations."autoscaling.alpha.kubernetes.io/current-metrics"' + jsonPointers: + - /metadata/annotations/autoscaling.alpha.kubernetes.io~1behavior + - /metadata/annotations/autoscaling.alpha.kubernetes.io~1conditions + - /metadata/annotations/autoscaling.alpha.kubernetes.io~1metrics + - /metadata/annotations/autoscaling.alpha.kubernetes.io~1current-metrics + resource.customizations.health.certmanager.k8s.io-Certificate: | hs = {} if obj.status ~= nil then @@ -203,13 +231,9 @@ data: # 'none' - disabled ignoreResourceStatusField: crd - # Configuration to add a config management plugin. - configManagementPlugins: | - - name: kasane - init: - command: [kasane, update] - generate: - command: [kasane, show] + # configuration to instruct controller to only watch for resources that it has permissions to list + # can be either empty, "normal" or "strict". By default, it is empty i.e. disabled. + resource.respectRBAC: "normal" # A set of settings that allow enabling or disabling the config management tool. # If unset, each defaults to "true". @@ -276,14 +300,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" @@ -331,3 +363,46 @@ data: - url: https://mycompany.splunk.com?search={{.metadata.namespace}} title: Splunk if: kind == "Pod" || kind == "Deployment" + + extension.config: | + extensions: + # Name defines the endpoint that will be used to register + # the extension route. + # Mandatory field. + - name: some-extension + backend: + # ConnectionTimeout is the maximum amount of time a dial to + # the extension server will wait for a connect to complete. + # Optional field. Default: 2 seconds + connectionTimeout: 2s + + # KeepAlive specifies the interval between keep-alive probes + # for an active network connection between the API server and + # the extension server. + # Optional field. Default: 15 seconds + keepAlive: 15s + + # IdleConnectionTimeout is the maximum amount of time an idle + # (keep-alive) connection between the API server and the extension + # server will remain idle before closing itself. + # Optional field. Default: 60 seconds + idleConnectionTimeout: 60s + + # MaxIdleConnections controls the maximum number of idle (keep-alive) + # connections between the API server and the extension server. + # Optional field. Default: 30 + maxIdleConnections: 30 + + services: + # URL is the address where the extension backend must be available. + # Mandatory field. + - url: http://httpbin.org + + # Cluster if provided, will have to match the application + # destination name or the destination server to have requests + # properly forwarded to this service URL. + # Optional field if only one service is specified. + # Mandatory if multiple services are specified. + cluster: + name: some-cluster + server: https://some-cluster diff --git a/docs/operator-manual/argocd-cmd-params-cm-yaml.md b/docs/operator-manual/argocd-cmd-params-cm-yaml.md new file mode 100644 index 0000000000000..1cdba010fcfc6 --- /dev/null +++ b/docs/operator-manual/argocd-cmd-params-cm-yaml.md @@ -0,0 +1,7 @@ +# argocd-cmd-params-cm.yaml example + +An example of an argocd-cmd-params-cm.yaml file: + +```yaml +{!docs/operator-manual/argocd-cmd-params-cm.yaml!} +``` diff --git a/docs/operator-manual/argocd-cmd-params-cm.yaml b/docs/operator-manual/argocd-cmd-params-cm.yaml index a694cc650b0d5..3cb79d85f3150 100644 --- a/docs/operator-manual/argocd-cmd-params-cm.yaml +++ b/docs/operator-manual/argocd-cmd-params-cm.yaml @@ -9,18 +9,19 @@ data: # Repo server address. (default "argocd-repo-server:8081") repo.server: "argocd-repo-server:8081" - # Dex server address (default "http://argocd-dex-server:5556") - dex.server: "http://argocd-dex-server:5556" - # Redis server hostname and port (e.g. argocd-redis:6379) redis.server: "argocd-redis:6379" - # Enable compression for data sent to Redis with the required compression algorithm. (default 'none') - redis.compression: none + # Enable compression for data sent to Redis with the required compression algorithm. (default 'gzip') + redis.compression: gzip # Redis database 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 @@ -57,8 +58,26 @@ data: controller.resource.health.persist: "true" # Cache expiration default (default 24h0m0s) controller.default.cache.expiration: "24h0m0s" + # Sharding algorithm used to balance clusters accross application controller shards (default "legacy") + 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") + server.listen.address: "0.0.0.0" + # Listen on given address for metrics (default "0.0.0.0") + server.metrics.listen.address: "0.0.0.0" # Run server without TLS server.insecure: "false" # Value for base href in index.html. Used if Argo CD is running behind reverse proxy under subpath different from / (default "/") @@ -67,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" @@ -78,14 +104,16 @@ data: server.repo.server.plaintext: "false" # Perform strict validation of TLS certificates when connecting to repo server server.repo.server.strict.tls: "false" + # Dex server address (default "http://argocd-dex-server:5556") + server.dex.server: "http://argocd-dex-server:5556" # Use a plaintext client (non-TLS) to connect to dex server server.dex.server.plaintext: "false" # Perform strict validation of TLS certificates when connecting to dex server server.dex.server.strict.tls: "false" # Disable client authentication server.disable.auth: "false" - # Enable GZIP compression - server.enable.gzip: "false" + # Toggle GZIP compression + server.enable.gzip: "true" # Set X-Frame-Options header in HTTP responses to value. To disable, set to "". (default "sameorigin") server.x.frame.options: "sameorigin" # The minimum SSL/TLS version that is acceptable (one of: 1.0|1.1|1.2|1.3) (default "1.2") @@ -108,6 +136,10 @@ data: server.enable.proxy.extension: "false" ## Repo-server properties + # Listen on given address for incoming connections (default "0.0.0.0") + reposerver.listen.address: "0.0.0.0" + # Listen on given address for metrics (default "0.0.0.0") + reposerver.metrics.listen.address: "0.0.0.0" # Set the logging format. One of: text|json (default "text") reposerver.log.format: "text" # Set the logging level. One of: debug|info|warn|error (default "info") @@ -143,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" @@ -150,8 +186,6 @@ data: ## ApplicationSet Controller Properties # Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager. applicationsetcontroller.enable.leader.election: "false" - # Argo CD repo namespace (default: argocd) - applicationsetcontroller.namespace: "" # "Modify how application is synced between the generator and the cluster. Default is 'sync' (create & update & delete), options: 'create-only', 'create-update' (no deletion), 'create-delete' (no update)" applicationsetcontroller.policy: "sync" # Print debug logs. Takes precedence over loglevel @@ -164,5 +198,24 @@ data: applicationsetcontroller.dryrun: "false" # Enable git submodule support applicationsetcontroller.enable.git.submodule: "true" - # Enables use of the Progressive Rollouts capability - applicationsetcontroller.enable.progressive.rollouts: "false" + # Enables use of the Progressive Syncs capability + applicationsetcontroller.enable.progressive.syncs: "false" + # A list of glob patterns specifying where to look for ApplicationSet resources. (default is only the ns where the controller is installed) + applicationsetcontroller.namespaces: "argocd,argocd-appsets-*" + # Path of the self-signed TLS certificate for SCM/PR Gitlab Generator + applicationsetcontroller.scm.root.ca.path: "" + # A comma separated list of allowed SCM providers (default "" is all SCM providers). + # Setting this field is required when using ApplicationSets-in-any-namespace, to prevent users from + # sending secrets from `tokenRef`s to disallowed `api` domains. + # The url used in the scm generator must exactly match one in the list + applicationsetcontroller.allowed.scm.providers: "https://git.example.com/,https://gitlab.example.com/" + # To disable SCM providers entirely (i.e. disable the SCM and PR generators), set this to "false". Default is "true". + applicationsetcontroller.enable.scm.providers: "false" + + ## Argo CD Notifications Controller Properties + # Set the logging level. One of: debug|info|warn|error (default "info") + 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/argocd-rbac-cm-yaml.md b/docs/operator-manual/argocd-rbac-cm-yaml.md new file mode 100644 index 0000000000000..c0dbcde428543 --- /dev/null +++ b/docs/operator-manual/argocd-rbac-cm-yaml.md @@ -0,0 +1,7 @@ +# argocd-rbac-cm.yaml example + +An example of an argocd-rbac-cm.yaml file: + +```yaml +{!docs/operator-manual/argocd-rbac-cm.yaml!} +``` diff --git a/docs/operator-manual/argocd-rbac-cm.yaml b/docs/operator-manual/argocd-rbac-cm.yaml index 12ec17f8e9e14..b68d93ecc4f89 100644 --- a/docs/operator-manual/argocd-rbac-cm.yaml +++ b/docs/operator-manual/argocd-rbac-cm.yaml @@ -19,6 +19,15 @@ data: # Grant all members of 'my-org:team-beta' admins g, my-org:team-beta, role:admin + # it is possible to provide additional entries in this configmap to compose the final policy csv. + # In this case the key must follow the pattern 'policy..csv'. Argo CD will concatenate + # all additional policies it finds with this pattern below the main one ('policy.csv'). This is useful + # to allow composing policies in config management tools like Kustomize, Helm, etc. + policy.overlay.csv: | + p, role:tester, applications, *, */*, allow + p, role:tester, projects, *, *, allow + g, my-org:team-qa, role:tester + # policy.default is the name of the default role which Argo CD will falls back to, when # authorizing API requests (optional). If omitted or empty, users may be still be able to login, # but will see no apps, projects, etc... diff --git a/docs/operator-manual/argocd-repo-creds-yaml.md b/docs/operator-manual/argocd-repo-creds-yaml.md new file mode 100644 index 0000000000000..dca214068405c --- /dev/null +++ b/docs/operator-manual/argocd-repo-creds-yaml.md @@ -0,0 +1,7 @@ +# argocd-repo-creds.yaml example + +An example of an argocd-repo-creds.yaml file: + +```yaml +{!docs/operator-manual/argocd-repo-creds.yaml!} +``` diff --git a/docs/operator-manual/argocd-repositories-yaml.md b/docs/operator-manual/argocd-repositories-yaml.md new file mode 100644 index 0000000000000..c9c99357c391a --- /dev/null +++ b/docs/operator-manual/argocd-repositories-yaml.md @@ -0,0 +1,7 @@ +# argocd-repositories.yaml example + +An example of an argocd-repositories.yaml file: + +```yaml +{!docs/operator-manual/argocd-repositories.yaml!} +``` diff --git a/docs/operator-manual/argocd-repositories.yaml b/docs/operator-manual/argocd-repositories.yaml index 9857b1601bc16..b6aa0715c389d 100644 --- a/docs/operator-manual/argocd-repositories.yaml +++ b/docs/operator-manual/argocd-repositories.yaml @@ -4,18 +4,33 @@ apiVersion: v1 kind: Secret metadata: - name: my-private-repo + name: my-private-https-repo namespace: argocd labels: argocd.argoproj.io/secret-type: repository stringData: - url: https://github.com/argoproj/my-private-repository + url: https://github.com/argoproj/argocd-example-apps password: my-password username: my-username + insecure: "true" # Ignore validity of server's TLS certificate. Defaults to "false" + forceHttpBasicAuth: "true" # Skip auth method negotiation and force usage of HTTP basic auth. Defaults to "false" + enableLfs: "true" # Enable git-lfs for this repository. Defaults to "false" +--- +apiVersion: v1 +kind: Secret +metadata: + name: my-private-ssh-repo + namespace: argocd + labels: + argocd.argoproj.io/secret-type: repository +stringData: + url: ssh://git@github.com/argoproj/argocd-example-apps sshPrivateKey: | -----BEGIN OPENSSH PRIVATE KEY----- ... -----END OPENSSH PRIVATE KEY----- + insecure: "true" # Do not perform a host key check for the server. Defaults to "false" + enableLfs: "true" # Enable git-lfs for this repository. Defaults to "false" --- apiVersion: v1 kind: Secret diff --git a/docs/operator-manual/argocd-secret-yaml.md b/docs/operator-manual/argocd-secret-yaml.md new file mode 100644 index 0000000000000..33a88a8e96ee2 --- /dev/null +++ b/docs/operator-manual/argocd-secret-yaml.md @@ -0,0 +1,7 @@ +# argocd-secret.yaml example + +An example of an argocd-secret.yaml file: + +```yaml +{!docs/operator-manual/argocd-secret.yaml!} +``` diff --git a/docs/operator-manual/argocd-ssh-known-hosts-cm-yaml.md b/docs/operator-manual/argocd-ssh-known-hosts-cm-yaml.md new file mode 100644 index 0000000000000..4a5977f61e842 --- /dev/null +++ b/docs/operator-manual/argocd-ssh-known-hosts-cm-yaml.md @@ -0,0 +1,7 @@ +# argocd-ssh-known-hosts-cm.yaml example + +An example of an argocd-ssh-known-hosts-cm.yaml file: + +```yaml +{!docs/operator-manual/argocd-ssh-known-hosts-cm.yaml!} +``` diff --git a/docs/operator-manual/argocd-ssh-known-hosts-cm.yaml b/docs/operator-manual/argocd-ssh-known-hosts-cm.yaml index 3b211363837a9..0f30fa5671662 100644 --- a/docs/operator-manual/argocd-ssh-known-hosts-cm.yaml +++ b/docs/operator-manual/argocd-ssh-known-hosts-cm.yaml @@ -7,12 +7,18 @@ metadata: name: argocd-ssh-known-hosts-cm data: ssh_known_hosts: | - bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== - github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== + # This file was automatically generated by hack/update-ssh-known-hosts.sh. DO NOT EDIT + [ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + [ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + [ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= + bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= + bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO + bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M= + github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H - github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= - github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl diff --git a/docs/operator-manual/argocd-tls-certs-cm-yaml.md b/docs/operator-manual/argocd-tls-certs-cm-yaml.md new file mode 100644 index 0000000000000..e18b54d6e117e --- /dev/null +++ b/docs/operator-manual/argocd-tls-certs-cm-yaml.md @@ -0,0 +1,7 @@ +# argocd-tls-certs-cm.yaml example + +An example of an argocd-tls-certs-cm.yaml file: + +```yaml +{!docs/operator-manual/argocd-tls-certs-cm.yaml!} +``` 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 d5492891d66bf..7c86075ff2f7f 100644 --- a/docs/operator-manual/config-management-plugins.md +++ b/docs/operator-manual/config-management-plugins.md @@ -1,3 +1,4 @@ + # Config Management Plugins Argo CD's "native" config management tools are Helm, Jsonnet, and Kustomize. If you want to use a different config @@ -18,53 +19,11 @@ The following sections will describe how to create, install, and use plugins. Ch ## Installing a config management plugin -There are two ways to install a Config Management Plugin: - -1. Add the plugin config to the Argo CD ConfigMap (**this method is deprecated and will be removed in a future - version**). The repo-server container will run your plugin's commands. This is a good option for a simple plugin that - requires only a few lines of code that fit nicely in the Argo CD ConfigMap. -2. Add the plugin as a sidecar to the repo-server Pod. - This is a good option for a more complex plugin that would clutter the Argo CD ConfigMap. A copy of the repository is - sent to the sidecar container as a tarball and processed individually per application, which makes it a good option - for [concurrent processing of monorepos](high_availability.md#enable-concurrent-processing). - -### Option 1: Configure plugins via Argo CD configmap (deprecated) - -The following changes are required to configure a new plugin: - -1. Make sure required binaries are available in `argocd-repo-server` pod. The binaries can be added via volume mounts or - using a custom image (see [custom_tools](custom_tools.md) for examples of both). -2. Register a new plugin in `argocd-cm` ConfigMap: - - :::yaml - data: - configManagementPlugins: | - - name: pluginName - init: # Optional command to initialize application source directory - command: ["sample command"] - args: ["sample args"] - generate: # Command to generate manifests YAML - command: ["sample command"] - args: ["sample args"] - lockRepo: true # Defaults to false. See below. - - The `generate` command must print a valid YAML or JSON stream to stdout. Both `init` and `generate` commands are executed inside the application source directory or in `path` when specified for the app. - -3. [Create an Application which uses your new CMP](#using-a-cmp). - -More CMP examples are available in [argocd-example-apps](https://github.com/argoproj/argocd-example-apps/tree/master/plugins). - -!!!note "Repository locking" - If your plugin makes use of `git` (e.g. `git crypt`), it is advised to set - `lockRepo` to `true` so that your plugin will have exclusive access to the - repository at the time it is executed. Otherwise, two applications synced - at the same time may result in a race condition and sync failure. - -### Option 2: Configure plugin via sidecar +### Sidecar plugin An operator can configure a plugin tool via a sidecar to repo-server. The following changes are required to configure a new plugin: -#### 1. Write the plugin configuration file +#### Write the plugin configuration file Plugins will be configured via a ConfigManagementPlugin manifest located inside the plugin container. @@ -75,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. @@ -84,7 +45,8 @@ spec: command: [sh] args: [-c, 'echo "Initializing..."'] # The generate command runs in the Application source directory each time manifests are generated. Standard output - # must be ONLY valid YAML manifests. A non-zero exit code will fail manifest generation. + # 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] @@ -92,12 +54,13 @@ spec: - | echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"Foo\": \"$ARGOCD_ENV_FOO\", \"KubeVersion\": \"$KUBE_VERSION\", \"KubeApiVersion\": \"$KUBE_API_VERSIONS\",\"Bar\": \"baz\"}}}" # The discovery config is applied to a repository. If every configured discovery tool matches, then the plugin may be - # used to generate manifests for Applications using the repository. + # used to generate manifests for Applications using the repository. If the discovery config is omitted then the plugin + # will not match any application but can still be invoked explicitly by specifying the plugin name in the app spec. # Only one of fileName, find.glob, or find.command should be specified. If multiple are specified then only the # first (in that order) is evaluated. discover: - # fileName is a glob pattern (https://pkg.go.dev/path/filepath#Glob) that is applied to the repository's root - # directory (not the Application source directory). If there is a match, this plugin may be used for the repository. + # fileName is a glob pattern (https://pkg.go.dev/path/filepath#Glob) that is applied to the Application's source + # directory. If there is a match, this plugin may be used for the Application. fileName: "./subdir/s*.yaml" find: # This does the same thing as fileName, but it supports double-start (nested directory) glob patterns. @@ -146,13 +109,17 @@ spec: # The command is run in an Application's source directory. Standard output must be JSON matching the schema of the # 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 ``` !!! note While the ConfigManagementPlugin _looks like_ a Kubernetes object, it is not actually a custom resource. It only follows kubernetes-style spec conventions. -The `generate` command must print a valid YAML stream to stdout. Both `init` and `generate` commands are executed inside the application source directory. +The `generate` command must print a valid Kubernetes YAML or JSON object stream to stdout. Both `init` and `generate` commands are executed inside the application source directory. The `discover.fileName` is used as [glob](https://pkg.go.dev/path/filepath#Glob) pattern to determine whether an application repository is supported by the plugin or not. @@ -167,7 +134,7 @@ If `discover.fileName` is not provided, the `discover.find.command` is executed application repository is supported by the plugin or not. The `find` command should return a non-error exit code and produce output to stdout when the application source type is supported. -#### 2. Place the plugin configuration file in the sidecar +#### Place the plugin configuration file in the sidecar Argo CD expects the plugin configuration file to be located at `/home/argocd/cmp-server/config/plugin.yaml` in the sidecar. @@ -202,7 +169,7 @@ data: fileName: "./subdir/s*.yaml" ``` -#### 3. Register the plugin sidecar +#### Register the plugin sidecar To install a plugin, patch argocd-repo-server to run the plugin container as a sidecar, with argocd-cmp-server as its entrypoint. You can use either off-the-shelf or custom-built plugin image as sidecar image. For example: @@ -245,99 +212,76 @@ volumes: Plugin commands have access to -1. The system environment variables (of the repo-server container for argocd-cm plugins or of the sidecar for sidecar plugins) +1. The system environment variables of the sidecar 2. [Standard build environment variables](../user-guide/build-environment.md) 3. Variables in the Application spec (References to system and build variables will get interpolated in the variables' values): -```yaml -apiVersion: argoproj.io/v1alpha1 -kind: Application -spec: - source: - plugin: - env: - - name: FOO - value: bar - - name: REV - value: test-$ARGOCD_APP_REVISION -``` - -!!! note - The `discover.command` command only has access to the above environment starting with v2.4. - -Before reaching the `init.command`, `generate.command`, and `discover.command` commands, Argo CD prefixes all -user-supplied environment variables (#3 above) with `ARGOCD_ENV_`. This prevents users from directly setting -potentially-sensitive environment variables. - -If your plugin was written before 2.4 and depends on user-supplied environment variables, then you will need to update -your plugin's behavior to work with 2.4. If you use a third-party plugin, make sure they explicitly advertise support -for 2.4. - -4. (Starting in v2.4) Parameters in the Application spec: - -```yaml -apiVersion: argoproj.io/v1alpha1 -kind: Application -spec: - source: - plugin: - parameters: - - name: values-files - array: [values-dev.yaml] - - name: helm-parameters - map: - image.tag: v1.2.3 -``` - -The parameters are available as JSON in the `ARGOCD_APP_PARAMETERS` environment variable. The example above would -produce this JSON: - -```json -[{"name": "values-files", "array": ["values-dev.yaml"]}, {"name": "helm-parameters", "map": {"image.tag": "v1.2.3"}}] -``` - -!!! note - Parameter announcements, even if they specify defaults, are _not_ sent to the plugin in `ARGOCD_APP_PARAMETERS`. - Only parameters explicitly set in the Application spec are sent to the plugin. It is up to the plugin to apply - the same defaults as the ones announced to the UI. - -The same parameters are also available as individual environment variables. The names of the environment variables -follows this convention: - -```yaml - - name: some-string-param - string: some-string-value - # PARAM_SOME_STRING_PARAM=some-string-value + apiVersion: argoproj.io/v1alpha1 + kind: Application + spec: + source: + plugin: + env: + - name: FOO + value: bar + - name: REV + value: test-$ARGOCD_APP_REVISION + + Before reaching the `init.command`, `generate.command`, and `discover.find.command` commands, Argo CD prefixes all + user-supplied environment variables (#3 above) with `ARGOCD_ENV_`. This prevents users from directly setting + potentially-sensitive environment variables. + +4. Parameters in the Application spec: + + apiVersion: argoproj.io/v1alpha1 + kind: Application + spec: + source: + plugin: + parameters: + - name: values-files + array: [values-dev.yaml] + - name: helm-parameters + map: + image.tag: v1.2.3 - - name: some-array-param - value: [item1, item2] - # PARAM_SOME_ARRAY_PARAM_0=item1 - # PARAM_SOME_ARRAY_PARAM_1=item2 + The parameters are available as JSON in the `ARGOCD_APP_PARAMETERS` environment variable. The example above would + produce this JSON: - - name: some-map-param - map: - image.tag: v1.2.3 - # PARAM_SOME_MAP_PARAM_IMAGE_TAG=v1.2.3 -``` - -!!! warning - Sanitize/escape user input. As part of Argo CD's manifest generation system, config management plugins are treated with a level of trust. Be + [{"name": "values-files", "array": ["values-dev.yaml"]}, {"name": "helm-parameters", "map": {"image.tag": "v1.2.3"}}] + + !!! note + Parameter announcements, even if they specify defaults, are _not_ sent to the plugin in `ARGOCD_APP_PARAMETERS`. + Only parameters explicitly set in the Application spec are sent to the plugin. It is up to the plugin to apply + the same defaults as the ones announced to the UI. + + The same parameters are also available as individual environment variables. The names of the environment variables + follows this convention: + + - name: some-string-param + string: some-string-value + # PARAM_SOME_STRING_PARAM=some-string-value + + - name: some-array-param + value: [item1, item2] + # PARAM_SOME_ARRAY_PARAM_0=item1 + # PARAM_SOME_ARRAY_PARAM_1=item2 + + - name: some-map-param + map: + image.tag: v1.2.3 + # PARAM_SOME_MAP_PARAM_IMAGE_TAG=v1.2.3 + +!!! warning "Sanitize/escape user input" + As part of Argo CD's manifest generation system, config management plugins are treated with a level of trust. Be sure to escape user input in your plugin to prevent malicious input from causing unwanted behavior. - ## Using a config management plugin with an Application -If your CMP is defined in the `argocd-cm` ConfigMap, you can create a new Application using the CLI. Replace -`` with the name configured in `argocd-cm`. - -```bash -argocd app create --config-management-plugin -``` - -If your CMP is defined as a sidecar, you must manually define the Application manifest. You may leave the `name` field +You may leave the `name` field empty in the `plugin` section for the plugin to be automatically matched with the Application based on its discovery rules. If you do mention the name make sure it is either `-` if version is mentioned in the `ConfigManagementPlugin` spec or else just ``. When name is explicitly -specified only that particular plugin will be used iff it's discovery pattern/command matches the provided application repo. +specified only that particular plugin will be used iff its discovery pattern/command matches the provided application repo. ```yaml apiVersion: argoproj.io/v1alpha1 @@ -352,7 +296,6 @@ spec: targetRevision: HEAD path: guestbook plugin: - # For either argocd-cm- or sidecar-installed CMPs, you can pass environment variables to the CMP. env: - name: FOO value: bar @@ -365,7 +308,7 @@ If you don't need to set any environment variables, you can set an empty plugin ``` !!! important - If your sidecar CMP command runs too long, the command will be killed, and the UI will show an error. The CMP server + If your CMP command runs too long, the command will be killed, and the UI will show an error. The CMP server respects the timeouts set by the `server.repo.server.timeout.seconds` and `controller.repo.server.timeout.seconds` items in `argocd-cm`. Increase their values from the default of 60s. @@ -378,6 +321,8 @@ If you don't need to set any environment variables, you can set an empty plugin plugin configured through the `argocd-cm` ConfigMap to a sidecar, make sure to update the plugin name to either `-` if version was mentioned in the `ConfigManagementPlugin` spec or else just use ``. You can also remove the name altogether and let the automatic discovery to identify the plugin. +!!! note + If a CMP renders blank manfiests, and `prune` is set to `true`, Argo CD will automatically remove resources. CMP plugin authors should ensure errors are part of the exit code. Commonly something like `kustomize build . | cat` won't pass errors because of the pipe. Consider setting `set -o pipefail` so anything piped will pass errors on failure. ## Debugging a CMP @@ -390,6 +335,14 @@ If you are actively developing a sidecar-installed CMP, keep a few things in min image. If you're using a different, static tag, set `imagePullPolicy: Always` on the CMP's sidecar container. 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 +| Error Message | Cause | +| -- | -- | +| `no matches for kind "ConfigManagementPlugin" in version "argoproj.io/v1alpha1"` | The `ConfigManagementPlugin` CRD was deprecated in Argo CD 2.4 and removed in 2.8. This error means you've tried to put the configuration for your plugin directly into Kubernetes as a CRD. Refer to this [section of documentation](#write-the-plugin-configuration-file) for how to write the plugin configuration file and place it properly in the sidecar. | ## Plugin tar stream exclusions @@ -408,12 +361,11 @@ them with semicolons. ## Migrating from argocd-cm plugins -Installing plugins by modifying the argocd-cm ConfigMap is deprecated as of v2.4. Support will be completely removed in -a future release. +Installing plugins by modifying the argocd-cm ConfigMap is deprecated as of v2.4 and has been completely removed starting in v2.8. -The following will show how to convert an argocd-cm plugin to a sidecar plugin. +CMP plugins work by adding a sidecar to `argocd-repo-server` along with a configuration in that sidecar located at `/home/argocd/cmp-server/config/plugin.yaml`. A argocd-cm plugin can be easily converted with the following steps. -### 1. Convert the ConfigMap entry into a config file +### Convert the ConfigMap entry into a config file First, copy the plugin's configuration into its own YAML file. Take for example the following ConfigMap entry: @@ -424,7 +376,7 @@ data: init: # Optional command to initialize application source directory command: ["sample command"] args: ["sample args"] - generate: # Command to generate manifests YAML + generate: # Command to generate Kubernetes Objects in either YAML or JSON command: ["sample command"] args: ["sample args"] lockRepo: true # Defaults to false. See below. @@ -441,7 +393,7 @@ spec: init: # Optional command to initialize application source directory command: ["sample command"] args: ["sample args"] - generate: # Command to generate manifests YAML + generate: # Command to generate Kubernetes Objects in either YAML or JSON command: ["sample command"] args: ["sample args"] ``` @@ -450,17 +402,44 @@ spec: The `lockRepo` key is not relevant for sidecar plugins, because sidecar plugins do not share a single source repo directory when generating manifests. -### 2. Write discovery rules for your plugin +Next, we need to decide how this yaml is going to be added to the sidecar. We can either bake the yaml directly into the image, or we can mount it from a ConfigMap. -Sidecar plugins use discovery rules instead of a plugin name to match Applications to plugins. +If using a ConfigMap, our example would look like this: -Write rules applicable to your plugin [using the instructions above](#1-write-the-plugin-configuration-file) and add -them to your configuration file. +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: pluginName + namespace: argocd +data: + pluginName.yaml: | + apiVersion: argoproj.io/v1alpha1 + kind: ConfigManagementPlugin + metadata: + name: pluginName + spec: + init: # Optional command to initialize application source directory + command: ["sample command"] + args: ["sample args"] + generate: # Command to generate Kubernetes Objects in either YAML or JSON + command: ["sample command"] + args: ["sample args"] +``` -!!! note - After installing your sidecar plugin, you may remove the `name` field from the plugin config in your - Application specs for auto-discovery or update the name to `-` - if version was mentioned in the `ConfigManagementPlugin` spec or else just use ``. For example: +Then this would be mounted in our plugin sidecar. + +### Write discovery rules for your plugin + +Sidecar plugins can use either discovery rules or a plugin name to match Applications to plugins. If the discovery rule is omitted +then you have to explicitly specify the plugin by name in the app spec or else that particular plugin will not match any app. + +If you want to use discovery instead of the plugin name to match applications to your plugin, write rules applicable to +your plugin [using the instructions above](#1-write-the-plugin-configuration-file) and add them to your configuration +file. + +To use the name instead of discovery, update the name in your application manifest to `-` +if version was mentioned in the `ConfigManagementPlugin` spec or else just use ``. For example: ```yaml apiVersion: argoproj.io/v1alpha1 @@ -473,18 +452,44 @@ spec: name: pluginName # Delete this for auto-discovery (and set `plugin: {}` if `name` was the only value) or use proper sidecar plugin name ``` -### 3. Make sure the plugin has access to the tools it needs +### Make sure the plugin has access to the tools it needs Plugins configured with argocd-cm ran on the Argo CD image. This gave it access to all the tools installed on that image by default (see the [Dockerfile](https://github.com/argoproj/argo-cd/blob/master/Dockerfile) for base image and installed tools). -You can either use a stock image (like busybox) or design your own base image with the tools your plugin needs. For -security, avoid using image with more binaries installed than what your plugin actually needs. +You can either use a stock image (like busybox, or alpine/k8s) or design your own base image with the tools your plugin needs. For +security, avoid using images with more binaries installed than what your plugin actually needs. -### 4. Test the plugin +### Test the plugin After installing the plugin as a sidecar [according to the directions above](#installing-a-config-management-plugin), test it out on a few Applications before migrating all of them to the sidecar plugin. Once tests have checked out, remove the plugin entry from your argocd-cm ConfigMap. + +### Additional Settings + +#### Preserve repository files mode + +By default, config management plugin receives source repository files with reset file mode. This is done for security +reasons. If you want to preserve original file mode, you can set `preserveFileMode` to `true` in the plugin spec: + +!!! warning + Make sure you trust the plugin you are using. If you set `preserveFileMode` to `true` then the plugin might receive + files with executable permissions which can be a security risk. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ConfigManagementPlugin +metadata: + name: pluginName +spec: + init: + command: ["sample command"] + args: ["sample args"] + generate: + command: ["sample command"] + args: ["sample args"] + preserveFileMode: true +``` diff --git a/docs/operator-manual/core.md b/docs/operator-manual/core.md new file mode 100644 index 0000000000000..3d6e0a322c423 --- /dev/null +++ b/docs/operator-manual/core.md @@ -0,0 +1,99 @@ +# Argo CD Core + +## Introduction + +Argo CD Core is a different installation that runs Argo CD in headless +mode. With this installation, you will have a fully functional GitOps +engine capable of getting the desired state from Git repositories and +applying it in Kubernetes. + +The following groups of features won't be available in this +installation: + +- Argo CD RBAC model +- Argo CD API +- OIDC based authentication + +The following features will be partially available (see the +[usage](#using) section below for more details): + +- Argo CD Web UI +- Argo CD CLI +- Multi-tenancy (strictly GitOps based on git push permissions) + +A few use-cases that justify running Argo CD Core are: + +- As a cluster admin, I want to rely on Kubernetes RBAC only. +- As a devops engineer, I don't want to learn a new API or depend on + another CLI to automate my deployments. I want to rely on the + Kubernetes API only. +- As a cluster admin, I don't want to provide Argo CD UI or Argo CD + CLI to developers. + +## Architecture + +Because Argo CD is designed with a component based architecture in +mind, it is possible to have a more minimalist installation. In this +case fewer components are installed and yet the main GitOps +functionality remains operational. + +In the diagram below, the Core box, shows the components that will be +installed while opting for Argo CD Core: + +![Argo CD Core](../assets/argocd-core-components.png) + +Note that even if the Argo CD controller can run without Redis, it +isn't recommended. The Argo CD controller uses Redis as an important +caching mechanism reducing the load on Kube API and in Git. For this +reason, Redis is also included in this installation method. + +## Installing + +Argo CD Core can be installed by applying a single manifest file that +contains all the required resources. + +Example: + +``` +export ARGOCD_VERSION= +kubectl create namespace argocd +kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/$ARGOCD_VERSION/manifests/core-install.yaml +``` + +## Using + +Once Argo CD Core is installed, users will be able to interact with it +by relying on GitOps. The available Kubernetes resources will be the +`Application` and the `ApplicationSet` CRDs. By using those resources, +users will be able to deploy and manage applications in Kubernetes. + +It is still possible to use Argo CD CLI even when running Argo CD +Core. In this case, the CLI will spawn a local API server process that +will be used to handle the CLI command. Once the command is concluded, +the local API Server process will also be terminated. This happens +transparently for the user with no additional command required. Note +that Argo CD Core will rely only on Kubernetes RBAC and the user (or +the process) invoking the CLI needs to have access to the Argo CD +namespace with the proper permission in the `Application` and +`ApplicationSet` resources for executing a given command. + +To use Argo CD CLI in core mode, it is required to pass the `--core` +flag with the `login` subcommand. + +Example: + +```bash +kubectl config set-context --current --namespace=argocd # change current kube context to argocd namespace +argocd login --core +``` + +Similarly, users can also run the Web UI locally if they prefer to +interact with Argo CD using this method. The Web UI can be started +locally by running the following command: + +``` +argocd admin dashboard -n argocd +``` + +Argo CD Web UI will be available at `http://localhost:8080` + diff --git a/docs/operator-manual/custom-styles.md b/docs/operator-manual/custom-styles.md index 21fa79efeeb2f..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 @@ -56,7 +56,7 @@ metadata: name: argocd-styles-cm data: my-styles.css: | - .nav-bar { + .sidebar { background: linear-gradient(to bottom, #999, #777, #333, #222, #111); } ``` @@ -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 8e3ff49fbda28..3830cb610796a 100644 --- a/docs/operator-manual/declarative-setup.md +++ b/docs/operator-manual/declarative-setup.md @@ -8,16 +8,16 @@ All resources, including `Application` and `AppProject` specs, have to be instal ### Atomic configuration -| Sample File | Resource Name | Kind | Description | -|-------------|---------------|------|-------------| -| [`argocd-cm.yaml`](argocd-cm.yaml) | argocd-cm | ConfigMap | General Argo CD configuration | -| [`argocd-repositories.yaml`](argocd-repositories.yaml) | my-private-repo / istio-helm-repo / private-helm-repo / private-repo | Secrets | Sample repository connection details | -| [`argocd-repo-creds.yaml`](argocd-repo-creds.yaml) | argoproj-https-creds / argoproj-ssh-creds / github-creds / github-enterprise-creds | Secrets | Sample repository credential templates | -| [`argocd-cmd-params-cm.yaml`](argocd-cmd-params-cm.yaml) | argocd-cmd-params-cm | ConfigMap | Argo CD env variables configuration | -| [`argocd-secret.yaml`](argocd-secret.yaml) | argocd-secret | Secret | User Passwords, Certificates (deprecated), Signing Key, Dex secrets, Webhook secrets | -| [`argocd-rbac-cm.yaml`](argocd-rbac-cm.yaml) | argocd-rbac-cm | ConfigMap | RBAC Configuration | -| [`argocd-tls-certs-cm.yaml`](argocd-tls-certs-cm.yaml) | argocd-tls-certs-cm | ConfigMap | Custom TLS certificates for connecting Git repositories via HTTPS (v1.2 and later) | -| [`argocd-ssh-known-hosts-cm.yaml`](argocd-ssh-known-hosts-cm.yaml) | argocd-ssh-known-hosts-cm | ConfigMap | SSH known hosts data for connecting Git repositories via SSH (v1.2 and later) | +| Sample File | Resource Name | Kind | Description | +|-----------------------------------------------------------------------|------------------------------------------------------------------------------------|-----------|--------------------------------------------------------------------------------------| +| [`argocd-cm.yaml`](argocd-cm-yaml.md) | argocd-cm | ConfigMap | General Argo CD configuration | +| [`argocd-repositories.yaml`](argocd-repositories-yaml.md) | my-private-repo / istio-helm-repo / private-helm-repo / private-repo | Secrets | Sample repository connection details | +| [`argocd-repo-creds.yaml`](argocd-repo-creds-yaml.md) | argoproj-https-creds / argoproj-ssh-creds / github-creds / github-enterprise-creds | Secrets | Sample repository credential templates | +| [`argocd-cmd-params-cm.yaml`](argocd-cmd-params-cm-yaml.md) | argocd-cmd-params-cm | ConfigMap | Argo CD env variables configuration | +| [`argocd-secret.yaml`](argocd-secret-yaml.md) | argocd-secret | Secret | User Passwords, Certificates (deprecated), Signing Key, Dex secrets, Webhook secrets | +| [`argocd-rbac-cm.yaml`](argocd-rbac-cm-yaml.md) | argocd-rbac-cm | ConfigMap | RBAC Configuration | +| [`argocd-tls-certs-cm.yaml`](argocd-tls-certs-cm-yaml.md) | argocd-tls-certs-cm | ConfigMap | Custom TLS certificates for connecting Git repositories via HTTPS (v1.2 and later) | +| [`argocd-ssh-known-hosts-cm.yaml`](argocd-ssh-known-hosts-cm-yaml.md) | argocd-ssh-known-hosts-cm | ConfigMap | SSH known hosts data for connecting Git repositories via SSH (v1.2 and later) | For each specific kind of ConfigMap and Secret resource, there is only a single supported resource name (as listed in the above table) - if you need to merge things you need to do it before creating them. @@ -26,11 +26,11 @@ For each specific kind of ConfigMap and Secret resource, there is only a single ### Multiple configuration objects -| Sample File | Kind | Description | -|-------------|------|-------------| -| [`application.yaml`](application.yaml) | Application | Example application spec | -| [`project.yaml`](project.yaml) | AppProject | Example project spec | -| - | Secret | Repository credentials | +| Sample File | Kind | Description | +|------------------------------------------------------------------|-------------|--------------------------| +| [`application.yaml`](../user-guide/application-specification.md) | Application | Example application spec | +| [`project.yaml`](./project-specification.md) | AppProject | Example project spec | +| - | Secret | Repository credentials | For `Application` and `AppProject` resources, the name of the resource equals the name of the application or project within Argo CD. This also means that application and project names are unique within a given Argo CD installation - you cannot have the same application name for two different applications. @@ -77,7 +77,7 @@ spec: ``` !!! warning - By default, deleting an application will not perform a cascade delete, which would delete its resources. You must add the finalizer if you want this behaviour - which you may well not want. + Without the `resources-finalizer.argocd.argoproj.io` finalizer, deleting an application will not delete the resources it manages. To perform a cascading delete, you must add the finalizer. See [App Deletion](../user-guide/app_deletion.md#about-the-deletion-finalizer). ```yaml metadata: @@ -98,7 +98,7 @@ The AppProject CRD is the Kubernetes resource object representing a logical grou It is defined by the following key pieces of information: * `sourceRepos` reference to the repositories that applications within the project can pull manifests from. -* `destinations` reference to clusters and namespaces that applications within the project can deploy into (don't use the `name` field, only the `server` field is matched). +* `destinations` reference to clusters and namespaces that applications within the project can deploy into. * `roles` list of entities with definitions of their access to resources within the project. !!!warning "Projects which can deploy to the Argo CD namespace grant admin access" @@ -209,7 +209,7 @@ metadata: argocd.argoproj.io/secret-type: repository stringData: type: git - url: git@github.com:argoproj/my-private-repository + url: git@github.com:argoproj/my-private-repository.git sshPrivateKey: | -----BEGIN OPENSSH PRIVATE KEY----- ... @@ -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", @@ -416,30 +416,51 @@ data: ### SSH known host public keys -If you are connecting repositories via SSH, Argo CD will need to know the SSH known hosts public key of the repository servers. You can manage the SSH known hosts data in the ConfigMap named `argocd-ssh-known-hosts-cm`. This ConfigMap contains a single key/value pair, with `ssh_known_hosts` as the key and the actual public keys of the SSH servers as data. As opposed to TLS configuration, the public key(s) of each single repository server Argo CD will connect via SSH must be configured, otherwise the connections to the repository will fail. There is no fallback. The data can be copied from any existing `ssh_known_hosts` file, or from the output of the `ssh-keyscan` utility. The basic format is ` `, one entry per line. +If you are configuring repositories to use SSH, Argo CD will need to know their SSH public keys. In order for Argo CD to connect via SSH the public key(s) for each repository server must be pre-configured in Argo CD (unlike TLS configuration), otherwise the connections to the repository will fail. + +You can manage the SSH known hosts data in the `argocd-ssh-known-hosts-cm` ConfigMap. This ConfigMap contains a single entry, `ssh_known_hosts`, with the public keys of the SSH servers as its value. The value can be filled in from any existing `ssh_known_hosts` file, or from the output of the `ssh-keyscan` utility (which is part of OpenSSH's client package). The basic format is ` `, one entry per line. + +Here is an example of running `ssh-keyscan`: +```bash +$ for host in bitbucket.org github.com gitlab.com ssh.dev.azure.com vs-ssh.visualstudio.com ; do ssh-keyscan $host 2> /dev/null ; done +bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M= +github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= +github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= +gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf +gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 +ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H +vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H +``` -An example ConfigMap object: +Here is an example `ConfigMap` object using the output from `ssh-keyscan` above: ```yaml apiVersion: v1 kind: ConfigMap metadata: - name: argocd-ssh-known-hosts-cm - namespace: argocd labels: - app.kubernetes.io/name: argocd-cm + app.kubernetes.io/name: argocd-ssh-known-hosts-cm app.kubernetes.io/part-of: argocd + name: argocd-ssh-known-hosts-cm data: ssh_known_hosts: | - bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== - github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== + # This file was automatically generated by hack/update-ssh-known-hosts.sh. DO NOT EDIT + [ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + [ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + [ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= + bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= + bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO + bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M= + github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H - github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= - github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl ``` !!! note @@ -469,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. @@ -515,6 +536,7 @@ The secret data must include following fields: * `server` - cluster api server url * `namespaces` - optional comma-separated list of namespaces which are accessible in that cluster. Cluster level resources would be ignored if namespace list is not empty. * `clusterResources` - optional boolean string (`"true"` or `"false"`) determining whether Argo CD can manage cluster-level resources on this cluster. This setting is used only if the list of managed namespaces is not empty. +* `project` - optional string to designate this as a project-scoped cluster. * `config` - JSON representation of following data structure: ```yaml @@ -527,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: @@ -568,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": "", @@ -580,6 +603,271 @@ stringData: } ``` +### EKS + +EKS cluster secret example using argocd-k8s-auth and [IRSA](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html): + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: mycluster-secret + labels: + argocd.argoproj.io/secret-type: cluster +type: Opaque +stringData: + name: "mycluster.example.com" + server: "https://mycluster.example.com" + config: | + { + "awsAuthConfig": { + "clusterName": "my-eks-cluster-name", + "roleARN": "arn:aws:iam:::role/" + }, + "tlsClientConfig": { + "insecure": false, + "caData": "" + } + } +``` + +Note that you should have IRSA enabled on your EKS cluster, create an appropriate IAM role which allows it to assume +other IAM roles (whichever `roleARN`s that Argo CD needs to assume) and have an assume role policy which allows +the argocd-application-controller and argocd-server pods to assume said role via OIDC. + +Example trust relationship config for `:role/`, which +is required for Argo CD to perform actions via IAM. Ensure that the cluster has an [IAM OIDC provider configured](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html) +for it. + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Federated": "arn:aws:iam:::oidc-provider/oidc.eks..amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE" + }, + "Action": "sts:AssumeRoleWithWebIdentity", + "Condition": { + "StringEquals": { + "oidc.eks..amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": ["system:serviceaccount:argocd:argocd-application-controller", "system:serviceaccount:argocd:argocd-server"], + "oidc.eks..amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com" + } + } + } + ] +} +``` + +The Argo CD management role also needs to be allowed to assume other roles, in this case we want it to assume +`arn:aws:iam:::role/` so that it can manage the cluster mapped to that role. This can be +extended to allow assumption of multiple roles, either as an explicit array of role ARNs or by using `*` where appropriate. + +```json +{ + "Version" : "2012-10-17", + "Statement" : { + "Effect" : "Allow", + "Action" : "sts:AssumeRole", + "Resource" : [ + ":role/" + ] + } + } +``` + +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 +kind: ServiceAccount +metadata: + annotations: + eks.amazonaws.com/role-arn: ":role/" + name: argocd-application-controller +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + annotations: + eks.amazonaws.com/role-arn: ":role/" + name: argocd-server +``` + +In turn, the `roleARN` of each managed cluster needs to be added to each respective cluster's `aws-auth` config map (see +[Enabling IAM principal access to your cluster](https://docs.aws.amazon.com/eks/latest/userguide/add-user-role.html)), as +well as having an assume role policy which allows it to be assumed by the Argo CD pod role. + +Example assume role policy for a cluster which is managed by Argo CD: + +```json +{ + "Version" : "2012-10-17", + "Statement" : { + "Effect" : "Allow", + "Action" : "sts:AssumeRole", + "Principal" : { + "AWS" : ":role/" + } + } + } +``` + +Example kube-system/aws-auth configmap for your cluster managed by Argo CD: + +```yaml +apiVersion: v1 +data: + # Other groups and accounts omitted for brevity. Ensure that no other rolearns and/or groups are inadvertently removed, + # or you risk borking access to your cluster. + # + # The group name is a RoleBinding which you use to map to a [Cluster]Role. See https://kubernetes.io/docs/reference/access-authn-authz/rbac/#role-binding-examples + mapRoles: | + - "groups": + - "" + "rolearn": ":role/" + "username": "" +``` + +#### Alternative EKS Authentication Methods +In some scenarios it may not be possible to use IRSA, such as when the Argo CD cluster is running on a different cloud +provider's platform. In this case, there are two options: +1. Use `execProviderConfig` to call the AWS authentication mechanism which enables the injection of environment variables to supply credentials +2. Leverage the new AWS profile option available in Argo CD release 2.10 + +Both of these options will require the steps involving IAM and the `aws-auth` config map (defined above) to provide the +principal with access to the cluster. + +##### Using execProviderConfig with Environment Variables +```yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: mycluster-secret + labels: + argocd.argoproj.io/secret-type: cluster +type: Opaque +stringData: + name: mycluster + server: https://mycluster.example.com + namespaces: "my,managed,namespaces" + clusterResources: "true" + config: | + { + "execProviderConfig": { + "command": "argocd-k8s-auth", + "args": ["aws", "--cluster-name", "my-eks-cluster"], + "apiVersion": "client.authentication.k8s.io/v1beta1", + "env": { + "AWS_REGION": "xx-east-1", + "AWS_ACCESS_KEY_ID": "{{ .aws_key_id }}", + "AWS_SECRET_ACCESS_KEY": "{{ .aws_key_secret }}", + "AWS_SESSION_TOKEN": "{{ .aws_token }}" + } + }, + "tlsClientConfig": { + "insecure": false, + "caData": "{{ .cluster_cert }}" + } + } +``` + +This example assumes that the role being attached to the credentials that have been supplied, if this is not the case +the role can be appended to the `args` section like so: + +```yaml +... + "args": ["aws", "--cluster-name", "my-eks-cluster", "--roleARN", "arn:aws:iam:::role/"], +... +``` +This construct can be used in conjunction with something like the External Secrets Operator to avoid storing the keys in +plain text and additionally helps to provide a foundation for key rotation. + +##### Using An AWS Profile For Authentication +The option to use profiles, added in release 2.10, provides a method for supplying credentials while still using the +standard Argo CD EKS cluster declaration with an additional command flag that points to an AWS credentials file: +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: mycluster-secret + labels: + argocd.argoproj.io/secret-type: cluster +type: Opaque +stringData: + name: "mycluster.com" + server: "https://mycluster.com" + config: | + { + "awsAuthConfig": { + "clusterName": "my-eks-cluster-name", + "roleARN": "arn:aws:iam:::role/", + "profile": "/mount/path/to/my-profile-file" + }, + "tlsClientConfig": { + "insecure": false, + "caData": "" + } + } +``` +This will instruct ArgoCD to read the file at the provided path and use the credentials defined within to authenticate to +AWS. The profile must be mounted in order for this to work. For example, the following values can be defined in a Helm +based ArgoCD deployment: + +```yaml +controller: + extraVolumes: + - name: my-profile-volume + secret: + secretName: my-aws-profile + items: + - key: my-profile-file + path: my-profile-file + extraVolumeMounts: + - name: my-profile-mount + mountPath: /mount/path/to + readOnly: true + +server: + extraVolumes: + - name: my-profile-volume + secret: + secretName: my-aws-profile + items: + - key: my-profile-file + path: my-profile-file + extraVolumeMounts: + - name: my-profile-mount + mountPath: /mount/path/to + readOnly: true +``` + +Where the secret is defined as follows: +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: my-aws-profile +type: Opaque +stringData: + my-profile-file: | + [default] + region = + aws_access_key_id = + aws_secret_access_key = + aws_session_token = +``` + +> ⚠️ Secret mounts are updated on an interval, not real time. If rotation is a requirement ensure the token lifetime outlives the mount update interval and the rotation process doesn't immediately invalidate the existing token + + +### GKE + GKE cluster secret example using argocd-k8s-auth and [Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity): ```yaml @@ -591,8 +879,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": { @@ -609,6 +897,108 @@ stringData: Note that you must enable Workload Identity on your GKE cluster, create GCP service account with appropriate IAM role and bind it to Kubernetes service account for argocd-application-controller and argocd-server (showing Pod logs on UI). See [Use Workload Identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity) and [Authenticating to the Kubernetes API server](https://cloud.google.com/kubernetes-engine/docs/how-to/api-server-authentication). +### AKS + +Azure cluster secret example using argocd-k8s-auth and [kubelogin](https://github.com/Azure/kubelogin). The option *azure* to the argocd-k8s-auth execProviderConfig encapsulates the *get-token* command for kubelogin. Depending upon which authentication flow is desired (devicecode, spn, ropc, msi, azurecli, workloadidentity), set the environment variable AAD_LOGIN_METHOD with this value. Set other appropriate environment variables depending upon which authentication flow is desired. + +|Variable Name|Description| +|-------------|-----------| +|AAD_LOGIN_METHOD|One of devicecode, spn, ropc, msi, azurecli, or workloadidentity| +|AAD_SERVICE_PRINCIPAL_CLIENT_CERTIFICATE|AAD client cert in pfx. Used in spn login| +|AAD_SERVICE_PRINCIPAL_CLIENT_ID|AAD client application ID| +|AAD_SERVICE_PRINCIPAL_CLIENT_SECRET|AAD client application secret| +|AAD_USER_PRINCIPAL_NAME|Used in the ropc flow| +|AAD_USER_PRINCIPAL_PASSWORD|Used in the ropc flow| +|AZURE_TENANT_ID|The AAD tenant ID.| +|AZURE_AUTHORITY_HOST|Used in the WorkloadIdentityLogin flow| +|AZURE_FEDERATED_TOKEN_FILE|Used in the WorkloadIdentityLogin flow| +|AZURE_CLIENT_ID|Used in the WorkloadIdentityLogin flow| + +In addition to the environment variables above, argocd-k8s-auth accepts two extra environment variables to set the AAD environment, and to set the AAD server application ID. The AAD server application ID will default to 6dae42f8-4368-4678-94ff-3960e28e3630 if not specified. See [here](https://github.com/azure/kubelogin#exec-plugin-format) for details. + +|Variable Name|Description| +|-------------|-----------| +|AAD_ENVIRONMENT_NAME|The azure environment to use, default of AzurePublicCloud| +|AAD_SERVER_APPLICATION_ID|The optional AAD server application ID, defaults to 6dae42f8-4368-4678-94ff-3960e28e3630| + +This is an example of using the [federated workload login flow](https://github.com/Azure/kubelogin#azure-workload-federated-identity-non-interactive). The federated token file needs to be mounted as a secret into argoCD, so it can be used in the flow. The location of the token file needs to be set in the environment variable AZURE_FEDERATED_TOKEN_FILE. + +If your AKS cluster utilizes the [Mutating Admission Webhook](https://azure.github.io/azure-workload-identity/docs/installation/mutating-admission-webhook.html) from the Azure Workload Identity project, follow these steps to enable the `argocd-application-controller` and `argocd-server` pods to use the federated identity: + +1. **Label the Pods**: Add the `azure.workload.identity/use: "true"` label to the `argocd-application-controller` and `argocd-server` pods. + +2. **Create Federated Identity Credential**: Generate an Azure federated identity credential for the `argocd-application-controller` and `argocd-server` service accounts. Refer to the [Federated Identity Credential](https://azure.github.io/azure-workload-identity/docs/topics/federated-identity-credential.html) documentation for detailed instructions. + +3. **Set the AZURE_CLIENT_ID**: Update the `AZURE_CLIENT_ID` in the cluster secret to match the client id of the newly created federated identity credential. + + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: mycluster-secret + labels: + argocd.argoproj.io/secret-type: cluster +type: Opaque +stringData: + name: mycluster.example.com + server: https://mycluster.example.com + config: | + { + "execProviderConfig": { + "command": "argocd-k8s-auth", + "env": { + "AAD_ENVIRONMENT_NAME": "AzurePublicCloud", + "AZURE_CLIENT_ID": "fill in client id", + "AZURE_TENANT_ID": "fill in tenant id", # optional, injected by workload identity mutating admission webhook if enabled + "AZURE_FEDERATED_TOKEN_FILE": "/opt/path/to/federated_file.json", # optional, injected by workload identity mutating admission webhook if enabled + "AZURE_AUTHORITY_HOST": "https://login.microsoftonline.com/", # optional, injected by workload identity mutating admission webhook if enabled + "AAD_LOGIN_METHOD": "workloadidentity" + }, + "args": ["azure"], + "apiVersion": "client.authentication.k8s.io/v1beta1" + }, + "tlsClientConfig": { + "insecure": false, + "caData": "" + } + } +``` + +This is an example of using the spn (service principal name) flow. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: mycluster-secret + labels: + argocd.argoproj.io/secret-type: cluster +type: Opaque +stringData: + name: mycluster.example.com + server: https://mycluster.example.com + config: | + { + "execProviderConfig": { + "command": "argocd-k8s-auth", + "env": { + "AAD_ENVIRONMENT_NAME": "AzurePublicCloud", + "AAD_SERVICE_PRINCIPAL_CLIENT_SECRET": "fill in your service principal client secret", + "AZURE_TENANT_ID": "fill in tenant id", + "AAD_SERVICE_PRINCIPAL_CLIENT_ID": "fill in your service principal client id", + "AAD_LOGIN_METHOD": "spn" + }, + "args": ["azure"], + "apiVersion": "client.authentication.k8s.io/v1beta1" + }, + "tlsClientConfig": { + "insecure": false, + "caData": "" + } + } +``` + ## Helm Chart Repositories Non standard Helm Chart repositories have to be registered explicitly. @@ -649,7 +1039,7 @@ stringData: ## Resource Exclusion/Inclusion -Resources can be excluded from discovery and sync so that Argo CD is unaware of them. For example, `events.k8s.io` and `metrics.k8s.io` are always excluded. Use cases: +Resources can be excluded from discovery and sync so that Argo CD is unaware of them. For example, the apiGroup/kind `events.k8s.io/*`, `metrics.k8s.io/*`, `coordination.k8s.io/Lease`, and `""/Endpoints` are always excluded. Use cases: * You have temporal issues and you want to exclude problematic resources. * There are many of a kind of resources that impacts Argo CD's performance. @@ -709,6 +1099,33 @@ Notes: * Invalid globs result in the whole rule being ignored. * If you add a rule that matches existing resources, these will appear in the interface as `OutOfSync`. +## Auto respect RBAC for controller + +Argocd controller can be restricted from discovering/syncing specific resources using just controller rbac, without having to manually configure resource exclusions. +This feature can be enabled by setting `resource.respectRBAC` key in argocd cm, once it is set the controller will automatically stop watching for resources +that it does not have the permission to list/access. Possible values for `resource.respectRBAC` are: + - `strict` : This setting checks whether the list call made by controller is forbidden/unauthorized and if it is, it will cross-check the permission by making a `SelfSubjectAccessReview` call for the resource. + - `normal` : This will only check whether the list call response is forbidden/unauthorized and skip `SelfSubjectAccessReview` call, to minimize any extra api-server calls. + - unset/empty (default) : This will disable the feature and controller will continue to monitor all resources. + +Users who are comfortable with an increase in kube api-server calls can opt for `strict` option while users who are concerned with higher api calls and are willing to compromise on the accuracy can opt for the `normal` option. + +Notes: + +* When set to use `strict` mode controller must have rbac permission to `create` a `SelfSubjectAccessReview` resource +* The `SelfSubjectAccessReview` request will be only made for the `list` verb, it is assumed that if `list` is allowed for a resource then all other permissions are also available to the controller. + +Example argocd cm with `resource.respectRBAC` set to `strict`: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cm +data: + resource.respectRBAC: "strict" +``` + ## Resource Custom Labels Custom Labels configured with `resource.customLabels` (comma separated string) will be displayed in the UI (for any resource that defines them). @@ -726,17 +1143,15 @@ based application which uses base Argo CD manifests from [https://github.com/arg Example of `kustomization.yaml`: ```yaml -bases: -- github.com/argoproj/argo-cd//manifests/cluster-install?ref=v1.0.1 - # additional resources like ingress rules, cluster and repository secrets. resources: +- github.com/argoproj/argo-cd//manifests/cluster-install?ref=stable - clusters-secrets.yaml - repos-secrets.yaml # changes to config maps -patchesStrategicMerge: -- overlays/argo-cd-cm.yaml +patches: +- path: overlays/argo-cd-cm.yaml ``` The live example of self managed Argo CD config is available at [https://cd.apps.argoproj.io](https://cd.apps.argoproj.io) and with configuration diff --git a/docs/operator-manual/deep_links.md b/docs/operator-manual/deep_links.md index 9b0778e045ac7..c166a1d25d75d 100644 --- a/docs/operator-manual/deep_links.md +++ b/docs/operator-manual/deep_links.md @@ -11,53 +11,68 @@ or individual resources (pods, services, etc.). ## Configuring Deep Links The configuration for Deep Links is present in `argocd-cm` as `.links` fields where -`` determines where it will be displayed. The possible values for `` are : -- `project` : all links under this field will show up in the project tab in the Argo CD UI -- `application` : all links under this field will show up in the application summary tab -- `resource` : all links under this field will show up in the resource (deployments, pods, services, etc.) summary tab - -Each link in the list has five subfields : -1. `title` : title/tag that will be displayed in the UI corresponding to that link -2. `url` : the actual URL where the deep link will redirect to, this field can be templated to use data from the - corresponing application, project or resource objects (depending on where it is located). This uses [text/template](pkg.go.dev/text/template) pkg for templating -3. `description` (optional) : a description for what the deep link is about -4. `icon.class` (optional) : a font-awesome icon class to be used when displaying the links in dropdown menus -5. `if` (optional) : a conditional statement that results in either `true` or `false`, it also has access to the same +`` determines where it will be displayed. The possible values for `` are: + +- `project`: all links under this field will show up in the project tab in the Argo CD UI +- `application`: all links under this field will show up in the application summary tab +- `resource`: all links under this field will show up in the resource (deployments, pods, services, etc.) summary tab + +Each link in the list has five subfields: + +1. `title`: title/tag that will be displayed in the UI corresponding to that link +2. `url`: the actual URL where the deep link will redirect to, this field can be templated to use data from the + corresponding application, project or resource objects (depending on where it is located). This uses [text/template](https://pkg.go.dev/text/template) pkg for templating +3. `description` (optional): a description for what the deep link is about +4. `icon.class` (optional): a font-awesome icon class to be used when displaying the links in dropdown menus +5. `if` (optional): a conditional statement that results in either `true` or `false`, it also has access to the same data as the `url` field. If the condition resolves to `true` the deep link will be displayed - else it will be hidden. If the field is omitted, by default the deep links will be displayed. This uses [antonmedv/expr](https://github.com/antonmedv/expr/tree/master/docs) for evaluating conditions !!!note - For resources of kind Secret the data fields are redacted but other fields are accessible for templating the deep links. + For resources of kind Secret the data fields are redacted but other fields are accessible for templating the deep links. !!!warning - Make sure to validate the url templates and inputs to prevent data leaks or possible generation of any malicious links. + Make sure to validate the url templates and inputs to prevent data leaks or possible generation of any malicious links. + +As mentioned earlier the links and conditions can be templated to use data from the resource, each category of links can access different types of data linked to that resource. +Overall we have these 4 resources available for templating in the system: + +- `app` or `application`: this key is used to access the application resource data. +- `resource`: this key is used to access values for the actual k8s resource. +- `cluster`: this key is used to access the related destination cluster data like name, server, namespaces etc. +- `project`: this key is used to access the project resource data. + +The above resources are accessible in particular link categories, here's a list of resources available in each category: +- `resource.links`: `resource`, `application`, `cluster` and `project` +- `application.links`: `app`/`application` and `cluster` +- `project.links`: `project` An example `argocd-cm.yaml` file with deep links and their variations : ```yaml # sample project level links project.links: | - - url: https://myaudit-system.com?project={{.metadata.name}} + - url: https://myaudit-system.com?project={{.project.metadata.name}} title: Audit description: system audit logs icon.class: "fa-book" # sample application level links application.links: | # pkg.go.dev/text/template is used for evaluating url templates - - url: https://mycompany.splunk.com?search={{.spec.destination.namespace}} + - url: https://mycompany.splunk.com?search={{.app.spec.destination.namespace}}&env={{.project.metadata.labels.env}} title: Splunk # conditionally show link e.g. for specific project # github.com/antonmedv/expr is used for evaluation of conditions - - url: https://mycompany.splunk.com?search={{.spec.destination.namespace}} + - url: https://mycompany.splunk.com?search={{.app.spec.destination.namespace}} title: Splunk - if: spec.project == "default" - - url: https://{{.metadata.annotations.splunkhost}}?search={{.spec.destination.namespace}} + if: application.spec.project == "default" + - url: https://{{.app.metadata.annotations.splunkhost}}?search={{.app.spec.destination.namespace}} title: Splunk - if: metadata.annotations.splunkhost + if: app.metadata.annotations.splunkhost != "" # sample resource level links resource.links: | - - url: https://mycompany.splunk.com?search={{.metadata.namespace}} + - url: https://mycompany.splunk.com?search={{.resource.metadata.name}}&env={{.project.metadata.labels.env}} title: Splunk - if: kind == "Pod" || kind == "Deployment" -``` \ No newline at end of file + if: resource.kind == "Pod" || resource.kind == "Deployment" +``` diff --git a/docs/operator-manual/disaster_recovery.md b/docs/operator-manual/disaster_recovery.md index 6bb52847d978a..97d2868051d65 100644 --- a/docs/operator-manual/disaster_recovery.md +++ b/docs/operator-manual/disaster_recovery.md @@ -15,13 +15,13 @@ export VERSION=v1.0.1 Export to a backup: ```bash -docker run -v ~/.kube:/home/argocd/.kube --rm argoproj/argocd:$VERSION argocd admin export > backup.yaml +docker run -v ~/.kube:/home/argocd/.kube --rm quay.io/argoproj/argocd:$VERSION argocd admin export > backup.yaml ``` Import from a backup: ```bash -docker run -i -v ~/.kube:/home/argocd/.kube --rm argoproj/argocd:$VERSION argocd admin import - < backup.yaml +docker run -i -v ~/.kube:/home/argocd/.kube --rm quay.io/argoproj/argocd:$VERSION argocd admin import - < backup.yaml ``` !!! note diff --git a/docs/operator-manual/dynamic-cluster-distribution.md b/docs/operator-manual/dynamic-cluster-distribution.md new file mode 100644 index 0000000000000..9d5d2104a1795 --- /dev/null +++ b/docs/operator-manual/dynamic-cluster-distribution.md @@ -0,0 +1,53 @@ +# Dynamic Cluster Distribution + +*Current Status: [Alpha][1] (Since v2.9.0)* + +By default, clusters are assigned to shards indefinitely. For users of the default, hash-based sharding algorithm, this +static assignment is fine: shards will always be roughly-balanced by the hash-based algorithm. But for users of the +[round-robin](high_availability.md#argocd-application-controller) or other custom shard assignment algorithms, this +static assignment can lead to unbalanced shards when replicas are added or removed. + +Starting v2.9, Argo CD supports a dynamic cluster distribution feature. When replicas are added or removed, the sharding +algorithm is re-run to ensure that the clusters are distributed according to the algorithm. If the algorithm is +well-balanced, like round-robin, then the shards will be well-balanced. + +Previously, the shard count was set via the `ARGOCD_CONTROLLER_REPLICAS` environment variable. Changing the environment +variable forced a restart of all application controller pods. Now, the shard count is set via the `replicas` field of the deployment, +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. 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. + +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) + +## Working of Dynamic Distribution + +To accomplish runtime distribution of clusters, the Application Controller uses a ConfigMap to associate a controller +pod with a shard number and a heartbeat to ensure that controller pods are still alive and handling their shard, in +effect, their share of the work. + +The Application Controller will create a new ConfigMap named `argocd-app-controller-shard-cm` to store the Controller <-> Shard mapping. The mapping would look like below for each shard: + +```yaml +ShardNumber : 0 +ControllerName : "argocd-application-controller-hydrxyt" +HeartbeatTime : "2009-11-17 20:34:58.651387237 +0000 UTC" +``` + +* `ControllerName`: Stores the hostname of the Application Controller pod +* `ShardNumber` : Stores the shard number managed by the controller pod +* `HeartbeatTime`: Stores the last time this heartbeat was updated. + +Controller Shard Mapping is updated in the ConfigMap during each readiness probe check of the pod, that is every 10 seconds (otherwise as configured). The controller will acquire the shard during every iteration of readiness probe check and try to update the ConfigMap with the `HeartbeatTime`. The default `HeartbeatDuration` after which the heartbeat should be updated is `10` seconds. If the ConfigMap was not updated for any controller pod for more than `3 * HeartbeatDuration`, then the readiness probe for the application pod is marked as `Unhealthy`. To increase the default `HeartbeatDuration`, you can set the environment variable `ARGOCD_CONTROLLER_HEARTBEAT_TIME` with the desired value. + +The new sharding mechanism does not monitor the environment variable `ARGOCD_CONTROLLER_REPLICAS` but instead reads the replica count directly from the Application Controller Deployment. The controller identifies the change in the number of replicas by comparing the replica count in the Application Controller Deployment and the number of mappings in the `argocd-app-controller-shard-cm` ConfigMap. + +In the scenario when the number of Application Controller replicas increases, a new entry is added to the list of mappings in the `argocd-app-controller-shard-cm` ConfigMap and the cluster distribution is triggered to re-distribute the clusters. + +In the scenario when the number of Application Controller replicas decreases, the mappings in the `argocd-app-controller-shard-cm` ConfigMap are reset and every controller acquires the shard again thus triggering the re-distribution of the clusters. + +[1]: https://github.com/argoproj/argoproj/blob/master/community/feature-status.md diff --git a/docs/operator-manual/health.md b/docs/operator-manual/health.md index 6cc12a8e72cfc..8566d6460e6db 100644 --- a/docs/operator-manual/health.md +++ b/docs/operator-manual/health.md @@ -3,9 +3,9 @@ ## 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 +### Deployment, ReplicaSet, StatefulSet, DaemonSet * Observed generation is equal to desired generation. * Number of **updated** replicas equals the number of desired replicas. @@ -114,12 +114,13 @@ In order to prevent duplication of the custom health check for potentially multi ```yaml resource.customizations: | - *.aws.crossplane.io/*: + "*.aws.crossplane.io/*": health.lua: | ... ``` - +!!!important + Please note the required quotes in the resource customization health section, if the wildcard starts with `*`. The `obj` is a global variable which contains the resource. The script must return an object with status and optional message field. The custom health check might return one of the following health statuses: @@ -136,9 +137,11 @@ setting `resource.customizations.useOpenLibs.`. In the following exa ```yaml data: - resource.customizations.useOpenLibs.cert-manager.io_Certificate: "true" - resource.customizations.health.cert-manager.io_Certificate: - -- Lua standard libraries are enabled for this script + resource.customizations: | + cert-manager.io/Certificate: + health.lua.useOpenLibs: true + health.lua: | + # Lua standard libraries are enabled for this script ``` ### Way 2. Contribute a Custom Health Check @@ -170,3 +173,36 @@ To test the implemented custom health checks, run `go test -v ./util/lua/`. The [PR#1139](https://github.com/argoproj/argo-cd/pull/1139) is an example of Cert Manager CRDs custom health check. Please note that bundled health checks with wildcards are not supported. + +## Health Checks + +An Argo CD App's health is inferred from the health of its immediate child resources (the resources represented in +source control). + +But the health of a resource is not inherited from child resources - it is calculated using only information about the +resource itself. A resource's status field may or may not contain information about the health of a child resource, and +the resource's health check may or may not take that information into account. + +The lack of inheritance is by design. A resource's health can't be inferred from its children because the health of a +child resource may not be relevant to the health of the parent resource. For example, a Deployment's health is not +necessarily affected by the health of its Pods. + +``` +App (healthy) +└── Deployment (healthy) + └── ReplicaSet (healthy) + └── Pod (healthy) + └── ReplicaSet (unhealthy) + └── Pod (unhealthy) +``` + +If you want the health of a child resource to affect the health of its parent, you need to configure the parent's health +check to take the child's health into account. Since only the parent resource's state is available to the health check, +the parent resource's controller needs to make the child resource's health available in the parent resource's status +field. + +``` +App (healthy) +└── CustomResource (healthy) <- This resource's health check needs to be fixed to mark the App as unhealthy + └── CustomChildResource (unhealthy) +``` diff --git a/docs/operator-manual/high_availability.md b/docs/operator-manual/high_availability.md index 0ae8a2edd9130..1b8a0aad3389a 100644 --- a/docs/operator-manual/high_availability.md +++ b/docs/operator-manual/high_availability.md @@ -1,10 +1,8 @@ # High Availability -Argo CD is largely stateless, all data is persisted as Kubernetes objects, which in turn is stored in Kubernetes' etcd. Redis is only used as a throw-away cache and can be lost. When lost, it will be rebuilt without loss of service. +Argo CD is largely stateless. All data is persisted as Kubernetes objects, which in turn is stored in Kubernetes' etcd. Redis is only used as a throw-away cache and can be lost. When lost, it will be rebuilt without loss of service. -A set of HA manifests are provided for users who wish to run Argo CD in a highly available manner. This runs more containers, and runs Redis in HA mode. - -[Manifests ⧉](https://github.com/argoproj/argo-cd/tree/master/manifests) +A set of [HA manifests](https://github.com/argoproj/argo-cd/tree/master/manifests/ha) are provided for users who wish to run Argo CD in a highly available manner. This runs more containers, and runs Redis in HA mode. > **NOTE:** The HA installation will require at least three different nodes due to pod anti-affinity roles in the > specs. Additionally, IPv6 only clusters are not supported. @@ -17,11 +15,11 @@ A set of HA manifests are provided for users who wish to run Argo CD in a highly The `argocd-repo-server` is responsible for cloning Git repository, keeping it up to date and generating manifests using the appropriate tool. -* `argocd-repo-server` fork/exec config management tool to generate manifests. The fork can fail due to lack of memory and limit on the number of OS threads. -The `--parallelismlimit` flag controls how many manifests generations are running concurrently and allows avoiding OOM kills. +* `argocd-repo-server` fork/exec config management tool to generate manifests. The fork can fail due to lack of memory or limit on the number of OS threads. +The `--parallelismlimit` flag controls how many manifests generations are running concurrently and helps avoid OOM kills. * the `argocd-repo-server` ensures that repository is in the clean state during the manifest generation using config management tools such as Kustomize, Helm -or custom plugin. As a result Git repositories with multiple applications might be affect repository server performance. +or custom plugin. As a result Git repositories with multiple applications might affect repository server performance. Read [Monorepo Scaling Considerations](#monorepo-scaling-considerations) for more information. * `argocd-repo-server` clones the repository into `/tmp` (or the path specified in the `TMPDIR` env variable). The Pod might run out of disk space if it has too many repositories @@ -30,7 +28,7 @@ or if the repositories have a lot of files. To avoid this problem mount a persis * `argocd-repo-server` uses `git ls-remote` to resolve ambiguous revisions such as `HEAD`, a branch or a tag name. This operation happens frequently and might fail. To avoid failed syncs use the `ARGOCD_GIT_ATTEMPTS_COUNT` environment variable to retry failed requests. -* `argocd-repo-server` Every 3m (by default) Argo CD checks for changes to the app manifests. Argo CD assumes by default that manifests only change when the repo changes, so it caches generated manifests (for 24h by default). With Kustomize remote bases, or Helm patch releases, the manifests can change even though the repo has not changed. By reducing the cache time, you can get the changes without waiting for 24h. Use `--repo-cache-expiration duration`, and we'd suggest in low volume environments you try '1h'. Bear in mind this will negate the benefit of caching if set too low. +* `argocd-repo-server` Every 3m (by default) Argo CD checks for changes to the app manifests. Argo CD assumes by default that manifests only change when the repo changes, so it caches the generated manifests (for 24h by default). With Kustomize remote bases, or in case a Helm chart gets changed without bumping its version number, the expected manifests can change even though the repo has not changed. By reducing the cache time, you can get the changes without waiting for 24h. Use `--repo-cache-expiration duration`, and we'd suggest in low volume environments you try '1h'. Bear in mind that this will negate the benefits of caching if set too low. * `argocd-repo-server` executes config management tools such as `helm` or `kustomize` and enforces a 90 second timeout. This timeout can be changed by using the `ARGOCD_EXEC_TIMEOUT` env variable. The value should be in the Go time duration string format, for example, `2m30s`. @@ -59,12 +57,13 @@ 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` -and repeat the number of replicas in the `ARGOCD_CONTROLLER_REPLICAS` environment variable. The strategic merge patch below -demonstrates changes required to configure two controller replicas. +controller replicas. To enable sharding, increase the number of replicas in `argocd-application-controller` `StatefulSet` +and repeat the number of replicas in the `ARGOCD_CONTROLLER_REPLICAS` environment variable. The strategic merge patch below demonstrates changes required to configure two controller replicas. + +* By default, the controller will update the cluster information every 10 seconds. If there is a problem with your cluster network environment that is causing the update time to take a long time, you can try modifying the environment variable `ARGO_CD_UPDATE_CLUSTER_INFO_TIMEOUT` to increase the timeout (the unit is seconds). ```yaml apiVersion: apps/v1 @@ -81,9 +80,50 @@ spec: - name: ARGOCD_CONTROLLER_REPLICAS value: "2" ``` +* In order to manually set the cluster's shard number, specify the optional `shard` property when creating a cluster. If not specified, it will be calculated on the fly by the application controller. + +* The shard distribution algorithm of the `argocd-application-controller` can be set by using the `--sharding-method` parameter. Supported sharding methods are : [legacy (default), round-robin]. `legacy` mode uses an `uid` based distribution (non-uniform). `round-robin` uses an equal distribution across all shards. The `--sharding-method` parameter can also be overriden by setting the key `controller.sharding.algorithm` in the `argocd-cmd-params-cm` `configMap` (preferably) or by setting the `ARGOCD_CONTROLLER_SHARDING_ALGORITHM` environment variable and by specifiying the same possible values. + +!!! warning "Alpha Feature" + The `round-robin` shard distribution algorithm is an experimental feature. Reshuffling is known to occur in certain scenarios with cluster removal. If the cluster at rank-0 is removed, reshuffling all clusters across shards will occur and may temporarily have negative performance impacts. + +* A cluster can be manually assigned and forced to a `shard` by patching the `shard` field in the cluster secret to contain the shard number, e.g. +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: mycluster-secret + labels: + argocd.argoproj.io/secret-type: cluster +type: Opaque +stringData: + shard: 1 + name: mycluster.example.com + server: https://mycluster.example.com + config: | + { + "bearerToken": "", + "tlsClientConfig": { + "insecure": false, + "caData": "" + } + } +``` * `ARGOCD_ENABLE_GRPC_TIME_HISTOGRAM` - environment variable that enables collecting RPC performance metrics. Enable it if you need to troubleshoot performance issues. Note: This metric is expensive to both query and store! +* `ARGOCD_CLUSTER_CACHE_LIST_PAGE_BUFFER_SIZE` - environment variable controlling the number of pages the controller + buffers in memory when performing a list operation against the K8s api server while syncing the cluster cache. This + is useful when the cluster contains a large number of resources and cluster sync times exceed the default etcd + compaction interval timeout. In this scenario, when attempting to sync the cluster cache, the application controller + may throw an error that the `continue parameter is too old to display a consistent list result`. Setting a higher + value for this environment variable configures the controller with a larger buffer in which to store pre-fetched + pages which are processed asynchronously, increasing the likelihood that all pages have been pulled before the etcd + compaction interval timeout expires. In the most extreme case, operators can set this value such that + `ARGOCD_CLUSTER_CACHE_LIST_PAGE_SIZE * ARGOCD_CLUSTER_CACHE_LIST_PAGE_BUFFER_SIZE` exceeds the largest resource + count (grouped by k8s api version, the granule of parallelism for list operations). In this case, all resources will + be buffered in memory -- no api server request will be blocked by processing. + **metrics** * `argocd_app_reconcile` - reports application reconciliation duration. Can be used to build reconciliation duration heat map to get a high-level reconciliation performance picture. @@ -92,12 +132,30 @@ non-preferred version and causes performance issues. ### argocd-server -The `argocd-server` is stateless and probably least likely to cause issues. You might consider increasing the number of replicas to 3 or more to ensure there is no downtime during upgrades. +The `argocd-server` is stateless and probably the least likely to cause issues. To ensure there is no downtime during upgrades, consider increasing the number of replicas to `3` or more and repeat the number in the `ARGOCD_API_SERVER_REPLICAS` environment variable. The strategic merge patch below +demonstrates this. + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: argocd-server +spec: + replicas: 3 + template: + spec: + containers: + - name: argocd-server + env: + - name: ARGOCD_API_SERVER_REPLICAS + value: "3" +``` **settings:** +* The `ARGOCD_API_SERVER_REPLICAS` environment variable is used to divide [the limit of concurrent login requests (`ARGOCD_MAX_CONCURRENT_LOGIN_REQUESTS_COUNT`)](./user-management/index.md#failed-logins-rate-limiting) between each replica. * The `ARGOCD_GRPC_MAX_SIZE_MB` environment variable allows specifying the max size of the server response message in megabytes. -The default value is 200. You might need to increase this for an Argo CD instance that manages 3000+ applications. +The default value is 200. You might need to increase this for an Argo CD instance that manages 3000+ applications. ### argocd-dex-server, argocd-redis @@ -112,8 +170,8 @@ Argo CD repo server maintains one repository clone locally and uses it for appli Argo CD determines if manifest generation might change local files in the local repository clone based on the config management tool and application settings. If the manifest generation has no side effects then requests are processed in parallel without a performance penalty. The following are known cases that might cause slowness and their workarounds: - * **Multiple Helm based applications pointing to the same directory in one Git repository:** ensure that your Helm chart doesn't have conditional -[dependencies](https://helm.sh/docs/chart_best_practices/dependencies/#conditions-and-tags) and create `.argocd-allow-concurrency` file in the chart directory. + * **Multiple Helm based applications pointing to the same directory in one Git repository:** for historical reasons Argo CD generates Helm manifests sequentially. To enable parallel generation set `ARGOCD_HELM_ALLOW_CONCURRENCY=true` to `argocd-repo-server` deployment or create `.argocd-allow-concurrency` file. + Future versions of Argo CD will enable this by default. * **Multiple Custom plugin based applications:** avoid creating temporal files during manifest generation and create `.argocd-allow-concurrency` file in the app directory, or use the sidecar plugin option, which processes each application using a temporary copy of the repository. @@ -184,4 +242,103 @@ spec: targetRevision: HEAD path: my-application # ... -``` \ No newline at end of file +``` + +### 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 disabled 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 MaxFloat64, which disables the limiter. + +### 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 b0fe078482d91..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 @@ -186,10 +223,10 @@ metadata: name: argocd-server-ingress namespace: argocd annotations: - kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/force-ssl-redirect: "true" nginx.ingress.kubernetes.io/ssl-passthrough: "true" spec: + ingressClassName: nginx rules: - host: argocd.example.com http: @@ -218,14 +255,13 @@ metadata: namespace: argocd annotations: cert-manager.io/cluster-issuer: letsencrypt-prod - kubernetes.io/ingress.class: nginx - kubernetes.io/tls-acme: "true" nginx.ingress.kubernetes.io/ssl-passthrough: "true" # If you encounter a redirect loop or are getting a 307 response code # then you need to force the nginx ingress to connect to the backend using HTTPS. # nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" spec: + ingressClassName: nginx rules: - host: argocd.example.com http: @@ -240,13 +276,14 @@ spec: tls: - hosts: - argocd.example.com - secretName: argocd-secret # do not change, this is provided by Argo CD + secretName: argocd-server-tls # as expected by argocd-server ``` -### Option 2: Multiple Ingress Objects And Hosts +### Option 2: SSL Termination at Ingress Controller -Since ingress-nginx Ingress supports only a single protocol per Ingress object, an alternative -way would be to define two Ingress objects. One for HTTP/HTTPS, and the other for gRPC: +An alternative approach is to perform the SSL termination at the Ingress. Since an `ingress-nginx` Ingress supports only a single protocol per Ingress object, two Ingress objects need to be defined using the `nginx.ingress.kubernetes.io/backend-protocol` annotation, one for HTTP/HTTPS and the other for gRPC. + +Each ingress will be for a different domain (`argocd.example.com` and `grpc.argocd.example.com`). This requires that the Ingress resources use different TLS `secretName`s to avoid unexpected behavior. HTTP/HTTPS Ingress: ```yaml @@ -256,10 +293,10 @@ metadata: name: argocd-server-http-ingress namespace: argocd annotations: - kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/force-ssl-redirect: "true" nginx.ingress.kubernetes.io/backend-protocol: "HTTP" spec: + ingressClassName: nginx rules: - http: paths: @@ -274,7 +311,7 @@ spec: tls: - hosts: - argocd.example.com - secretName: argocd-secret # do not change, this is provided by Argo CD + secretName: argocd-ingress-http ``` gRPC Ingress: @@ -285,9 +322,9 @@ metadata: name: argocd-server-grpc-ingress namespace: argocd annotations: - kubernetes.io/ingress.class: "nginx" nginx.ingress.kubernetes.io/backend-protocol: "GRPC" spec: + ingressClassName: nginx rules: - http: paths: @@ -302,7 +339,7 @@ spec: tls: - hosts: - grpc.argocd.example.com - secretName: argocd-secret # do not change, this is provided by Argo CD + secretName: argocd-ingress-grpc ``` The API server should then be run with TLS disabled. Edit the `argocd-server` deployment to add the @@ -414,6 +451,132 @@ Once we create this service, we can configure the Ingress to conditionally route - argocd.argoproj.io ``` +## [Istio](https://www.istio.io) +You can put Argo CD behind Istio using following configurations. Here we will achive both serving Argo CD behind istio and using subpath on Istio + +First we need to make sure that we can run Argo CD with subpath (ie /argocd). For this we have used install.yaml from argocd project as is + +```bash +curl -kLs -o install.yaml https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml +``` + +save following file as kustomization.yml + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- ./install.yaml + +patches: +- path: ./patch.yml +``` + +And following lines as patch.yml + +```yaml +# Use --insecure so Ingress can send traffic with HTTP +# --bashref /argocd is the subpath like https://IP/argocd +# env was added because of https://github.com/argoproj/argo-cd/issues/3572 error +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: argocd-server +spec: + template: + spec: + containers: + - args: + - /usr/local/bin/argocd-server + - --staticassets + - /shared/app + - --redis + - argocd-redis-ha-haproxy:6379 + - --insecure + - --basehref + - /argocd + - --rootpath + - /argocd + name: argocd-server + env: + - name: ARGOCD_MAX_CONCURRENT_LOGIN_REQUESTS_COUNT + value: "0" +``` + +After that install Argo CD (there should be only 3 yml file defined above in current directory ) + +```bash +kubectl apply -k ./ -n argocd --wait=true +``` + +Be sure you create secret for Isito ( in our case secretname is argocd-server-tls on argocd Namespace). After that we create Istio Resources + +```yaml +apiVersion: networking.istio.io/v1alpha3 +kind: Gateway +metadata: + name: argocd-gateway + namespace: argocd +spec: + selector: + istio: ingressgateway + servers: + - port: + number: 80 + name: http + protocol: HTTP + hosts: + - "*" + tls: + httpsRedirect: true + - port: + number: 443 + name: https + protocol: HTTPS + hosts: + - "*" + tls: + credentialName: argocd-server-tls + maxProtocolVersion: TLSV1_3 + minProtocolVersion: TLSV1_2 + mode: SIMPLE + cipherSuites: + - ECDHE-ECDSA-AES128-GCM-SHA256 + - ECDHE-RSA-AES128-GCM-SHA256 + - ECDHE-ECDSA-AES128-SHA + - AES128-GCM-SHA256 + - AES128-SHA + - ECDHE-ECDSA-AES256-GCM-SHA384 + - ECDHE-RSA-AES256-GCM-SHA384 + - ECDHE-ECDSA-AES256-SHA + - AES256-GCM-SHA384 + - AES256-SHA +--- +apiVersion: networking.istio.io/v1alpha3 +kind: VirtualService +metadata: + name: argocd-virtualservice + namespace: argocd +spec: + hosts: + - "*" + gateways: + - argocd-gateway + http: + - match: + - uri: + prefix: /argocd + route: + - destination: + host: argocd-server + port: + number: 80 +``` + +And now we can browse http://{{ IP }}/argocd (it will be rewritten to https://{{ IP }}/argocd + + ## Google Cloud load balancers with Kubernetes Ingress You can make use of the integration of GKE with Google Cloud to deploy Load Balancers using just Kubernetes objects. @@ -535,18 +698,18 @@ metadata: networking.gke.io/v1beta1.FrontendConfig: argocd-frontend-config spec: tls: - - secretName: secret-yourdomain-com + - secretName: secret-example-com rules: - - host: argocd.yourdomain.com - http: - paths: - - pathType: ImplementationSpecific - path: "/*" # "*" is needed. Without this, the UI Javascript and CSS will not load properly - backend: - service: - name: argocd-server - port: - number: 80 + - host: argocd.example.com + http: + paths: + - pathType: ImplementationSpecific + path: "/*" # "*" is needed. Without this, the UI Javascript and CSS will not load properly + backend: + service: + name: argocd-server + port: + number: 80 ``` If you use the version `1.21.3-gke.1600` or later, you should use the following Ingress resource: @@ -560,21 +723,21 @@ metadata: networking.gke.io/v1beta1.FrontendConfig: argocd-frontend-config spec: tls: - - secretName: secret-yourdomain-com + - secretName: secret-example-com rules: - - host: argocd.yourdomain.com - http: - paths: - - pathType: Prefix - path: "/" - backend: - service: - name: argocd-server - port: - number: 80 + - host: argocd.example.com + http: + paths: + - pathType: Prefix + path: "/" + backend: + service: + name: argocd-server + port: + 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: @@ -586,7 +749,7 @@ Once the DNS change is propagated, you're ready to use Argo with your Google Clo ## Authenticating through multiple layers of authenticating reverse proxies -ArgoCD endpoints may be protected by one or more reverse proxies layers, in that case, you can provide additional headers through the `argocd` CLI `--header` parameter to authenticate through those layers. +Argo CD endpoints may be protected by one or more reverse proxies layers, in that case, you can provide additional headers through the `argocd` CLI `--header` parameter to authenticate through those layers. ```shell $ argocd login : --header 'x-token1:foo' --header 'x-token2:bar' # can be repeated multiple times @@ -594,7 +757,7 @@ $ argocd login : --header 'x-token1:foo,x-token2:bar' # headers can ``` ## ArgoCD Server and UI Root Path (v1.5.3) -ArgoCD server and UI can be configured to be available under a non-root path (e.g. `/argo-cd`). +Argo CD server and UI can be configured to be available under a non-root path (e.g. `/argo-cd`). To do this, add the `--rootpath` flag into the `argocd-server` deployment command: ```yaml diff --git a/docs/operator-manual/installation.md b/docs/operator-manual/installation.md index 8778abe338be5..5782e5660868f 100644 --- a/docs/operator-manual/installation.md +++ b/docs/operator-manual/installation.md @@ -48,19 +48,17 @@ High Availability installation is recommended for production use. This bundle in ## Core -The core installation is most suitable for cluster administrators who independently use Argo CD and don't need multi-tenancy features. This installation -includes fewer components and is easier to setup. The bundle does not include the API server or UI, and installs the lightweight (non-HA) version of each component. +The Argo CD Core installation is primarily used to deploy Argo CD in +headless mode. This type of installation is most suitable for cluster +administrators who independently use Argo CD and don't need +multi-tenancy features. This installation includes fewer components +and is easier to setup. The bundle does not include the API server or +UI, and installs the lightweight (non-HA) version of each component. -The end-users need Kubernetes access to manage Argo CD. The `argocd` CLI has to be configured using the following commands: +Installation manifest is available at [core-install.yaml](https://github.com/argoproj/argo-cd/blob/master/manifests/core-install.yaml). -```bash -kubectl config set-context --current --namespace=argocd # change current kube context to argocd namespace -argocd login --core -``` - -The Web UI is also available and can be started using the `argocd admin dashboard` command. - -Installation manifests are available at [core-install.yaml](https://github.com/argoproj/argo-cd/blob/master/manifests/core-install.yaml). +For more details about Argo CD Core please refer to the [official +documentation](./core.md) ## Kustomize @@ -74,9 +72,12 @@ kind: Kustomization namespace: argocd resources: -- https://raw.githubusercontent.com/argoproj/argo-cd/v2.0.4/manifests/ha/install.yaml +- https://raw.githubusercontent.com/argoproj/argo-cd/v2.7.2/manifests/install.yaml ``` +For an example of this, see the [kustomization.yaml](https://github.com/argoproj/argoproj-deployments/blob/master/argocd/kustomization.yaml) +used to deploy the [Argoproj CI/CD infrastructure](https://github.com/argoproj/argoproj-deployments#argoproj-deployments). + ## Helm The Argo CD can be installed using [Helm](https://helm.sh/). The Helm chart is currently community maintained and available at @@ -84,17 +85,10 @@ The Argo CD can be installed using [Helm](https://helm.sh/). The Helm chart is c ## Supported versions -Similar to the Kubernetes project, the supported versions of Argo CD at any given point in time are the latest patch releases for the N -and N - 1 minor versions. -These Argo CD versions are supported on the same versions of Kubernetes that are supported by Kubernetes itself (normally the last 3 released versions). +For detailed information regarding Argo CD's version support policy, please refer to the [Release Process and Cadence documentation](https://argo-cd.readthedocs.io/en/stable/developer-guide/release-process-and-cadence/). -Essentially the Argo CD project follows the same support scheme as Kubernetes but for N, N-1 while Kubernetes supports N, N-1, N-2 versions. +## Tested versions -For example if the latest minor version of ArgoCD are 2.4.3 and 2.3.5 while supported Kubernetes versions are 1.24, 1.23 and 1.22 then the following combinations are supported: +The following table shows the versions of Kubernetes that are tested with each version of Argo CD. -* Argo CD 2.4.3 on Kubernetes 1.24 -* Argo CD 2.4.3 on Kubernetes 1.23 -* Argo CD 2.4.3 on Kubernetes 1.22 -* Argo CD 2.3.5 on Kubernetes 1.24 -* Argo CD 2.3.5 on Kubernetes 1.23 -* Argo CD 2.3.5 on Kubernetes 1.22 \ No newline at end of file +{!docs/operator-manual/tested-kubernetes-versions.md!} diff --git a/docs/operator-manual/metrics.md b/docs/operator-manual/metrics.md index da816f82f519b..a3ddbfe9904d3 100644 --- a/docs/operator-manual/metrics.md +++ b/docs/operator-manual/metrics.md @@ -7,13 +7,13 @@ 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 ArgoCD. | -| `argocd_app_k8s_request_total` | counter | Number of kubernetes requests executed during application reconciliation | +| `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_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. | @@ -23,7 +23,7 @@ Metrics about applications. Scraped at the `argocd-metrics:8082/metrics` endpoin | `argocd_redis_request_duration` | histogram | Redis requests duration. | | `argocd_redis_request_total` | counter | Number of redis requests executed during application reconciliation | -If you use ArgoCD with many application and project creation and deletion, +If you use Argo CD with many application and project creation and deletion, the metrics page will keep in cache your application and project's history. If you are having issues because of a large number of metrics cardinality due to deleted resources, you can schedule a metrics reset to clean the @@ -32,16 +32,16 @@ history with an application controller flag. Example: ### Exposing Application labels as Prometheus metrics -There are use-cases where ArgoCD Applications contain labels that are desired to be exposed as Prometheus metrics. +There are use-cases where Argo CD Applications contain labels that are desired to be exposed as Prometheus metrics. Some examples are: * Having the team name as a label to allow routing alerts to specific receivers * Creating dashboards broken down by business units As the Application labels are specific to each company, this feature is disabled by default. To enable it, add the -`--metrics-application-labels` flag to the ArgoCD application controller. +`--metrics-application-labels` flag to the Argo CD application controller. -The example below will expose the ArgoCD Application labels `team-name` and `business-unit` to Prometheus: +The example below will expose the Argo CD Application labels `team-name` and `business-unit` to Prometheus: containers: - command: @@ -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. @@ -79,14 +81,15 @@ 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_git_fetch_fail_total` | counter | Number of git fetch requests failures 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 +151,54 @@ 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 + labels: + release: prometheus-operator +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/catalog.md b/docs/operator-manual/notifications/catalog.md index 8f413ac7eb5b3..add7084304b98 100644 --- a/docs/operator-manual/notifications/catalog.md +++ b/docs/operator-manual/notifications/catalog.md @@ -62,8 +62,7 @@ slack: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -90,8 +89,7 @@ teams: "value": "{{.app.status.sync.revision}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" @@ -145,8 +143,7 @@ slack: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -169,8 +166,7 @@ teams: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" @@ -224,8 +220,7 @@ slack: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -252,8 +247,7 @@ teams: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" @@ -307,8 +301,7 @@ slack: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -335,8 +328,7 @@ teams: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" @@ -394,8 +386,7 @@ slack: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -418,8 +409,7 @@ teams: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" @@ -472,8 +462,7 @@ slack: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -500,8 +489,7 @@ teams: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" 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 dafb87169eb14..eccca906ae91b 100644 --- a/docs/operator-manual/notifications/index.md +++ b/docs/operator-manual/notifications/index.md @@ -1,4 +1,4 @@ -# Overview +# Notifications Overview Argo CD Notifications continuously monitors Argo CD applications and provides a flexible way to notify users about important changes in the application state. Using a flexible mechanism of @@ -10,37 +10,106 @@ So you can just use them instead of reinventing new ones. * Install Triggers and Templates from the catalog -``` -kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/notifications_catalog/install.yaml -``` + ```bash + kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/notifications_catalog/install.yaml + ``` * Add Email username and password token to `argocd-notifications-secret` secret -```bash -export EMAIL_USER= -export PASSWORD= -kubectl apply -n argocd -f - << EOF + ```bash + EMAIL_USER= + PASSWORD= + + kubectl apply -n argocd -f - << EOF + apiVersion: v1 + kind: Secret + metadata: + name: argocd-notifications-secret + stringData: + email-username: $EMAIL_USER + email-password: $PASSWORD + type: Opaque + EOF + ``` + +* Register Email notification service + + ```bash + kubectl patch cm argocd-notifications-cm -n argocd --type merge -p '{"data": {"service.email.gmail": "{ username: $email-username, password: $email-password, host: smtp.gmail.com, port: 465, from: $email-username }" }}' + ``` + +* Subscribe to notifications by adding the `notifications.argoproj.io/subscribe.on-sync-succeeded.slack` annotation to the Argo CD application or project: + + ```bash + kubectl patch app -n argocd -p '{"metadata": {"annotations": {"notifications.argoproj.io/subscribe.on-sync-succeeded.slack":""}}}' --type merge + ``` + +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: Secret +kind: ConfigMap metadata: - name: argocd-notifications-secret -stringData: - email-username: $EMAIL_USER - email-password: $PASSWORD -type: Opaque -EOF + name: argocd-cmd-params-cm +data: + application.namespaces: app-team-one, app-team-two + notificationscontroller.selfservice.enabled: "true" ``` -* Register Email notification service +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. -```bash -kubectl patch cm argocd-notifications-cm -n argocd --type merge -p '{"data": {"service.email.gmail": "{ username: $email-username, password: $email-password, host: smtp.gmail.com, port: 465, from: $email-username }" }}' -``` +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. -* Subscribe to notifications by adding the `notifications.argoproj.io/subscribe.on-sync-succeeded.slack` annotation to the Argo CD application or project: +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: +``` -```bash -kubectl patch app -n argocd -p '{"metadata": {"annotations": {"notifications.argoproj.io/subscribe.on-sync-succeeded.slack":""}}}' --type merge +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: "" ``` -Try syncing an application to get notified when the sync is completed. +!!! 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/monitoring.md b/docs/operator-manual/notifications/monitoring.md index 31b6f45cf4392..a0aabbaae1f09 100644 --- a/docs/operator-manual/notifications/monitoring.md +++ b/docs/operator-manual/notifications/monitoring.md @@ -3,7 +3,7 @@ The Argo CD Notification controller serves Prometheus metrics on port 9001. !!! note - Metrics port might be changed using the `--metrics-port` flag in `argocd-notifications-controller` deployment. + The metrics port can be changed using the `--metrics-port` flag in `argocd-notifications-controller` deployment. ## Metrics The following metrics are available: @@ -15,7 +15,7 @@ The following metrics are available: * `template` - notification template name * `notifier` - notification service name -* `succeeded` - flag that indicates if notification was successfully sent or failed. +* `succeeded` - flag that indicates if notification was successfully sent or failed ### `argocd_notifications_trigger_eval_total` @@ -23,8 +23,8 @@ The following metrics are available: Labels: * `name` - trigger name -* `triggered` - flag that indicates if trigger condition returned true of false. +* `triggered` - flag that indicates if trigger condition returned true of false -# Examples: +## Examples -* Grafana Dashboard: [grafana-dashboard.json](grafana-dashboard.json) \ No newline at end of file +* Grafana Dashboard: [grafana-dashboard.json](grafana-dashboard.json) 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 new file mode 100755 index 0000000000000..5331533826348 --- /dev/null +++ b/docs/operator-manual/notifications/services/awssqs.md @@ -0,0 +1,119 @@ +# AWS SQS + +## Parameters + +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 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 variable or via env variable AWS_SECRET_ACCESS_KEY +* `account` optional, external accountId of the queue +* `endpointUrl` optional, useful for development with localstack + +## Example + +### Using Secret for credential retrieval: + +Resource Annotation: +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + annotations: + notifications.argoproj.io/subscribe.on-deployment-ready.awssqs: "overwrite-myqueue" +``` + +* ConfigMap +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-notifications-cm +data: + service.awssqs: | + region: "us-east-2" + queue: "myqueue" + account: "1234567" + key: "$awsaccess_key" + secret: "$awsaccess_secret" + + template.deployment-ready: | + message: | + Deployment {{.obj.metadata.name}} is ready! + + trigger.on-deployment-ready: | + - when: any(obj.status.conditions, {.type == 'Available' && .status == 'True'}) + send: [deployment-ready] + - oncePer: obj.metadata.annotations["generation"] + +``` + Secret +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: +stringData: + awsaccess_key: test + awsaccess_secret: test +``` + + +### Minimal configuration using AWS Env variables + +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: + +```bash +export AWS_ACCESS_KEY_ID="test" +export AWS_SECRET_ACCESS_KEY="test" +export AWS_DEFAULT_REGION="us-east-1" +``` + +Resource Annotation: +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + annotations: + notifications.argoproj.io/subscribe.on-deployment-ready.awssqs: "" +``` + +* ConfigMap +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-notifications-cm +data: + service.awssqs: | + queue: "myqueue" + + template.deployment-ready: | + message: | + Deployment {{.obj.metadata.name}} is ready! + + trigger.on-deployment-ready: | + - when: any(obj.status.conditions, {.type == 'Available' && .status == 'True'}) + send: [deployment-ready] + - 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 e3c4b7d9e6380..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 @@ -46,13 +46,13 @@ data: ## Template -Notification templates support specifying subject for email notifications: +[Notification templates](../templates.md) support specifying subject for email notifications: ```yaml 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 953e55bd65d5f..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 +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: @@ -58,15 +58,35 @@ metadata: ![](https://user-images.githubusercontent.com/18019529/108520497-168ce180-730e-11eb-93cb-b0b91f99bdc5.png) -If the message is set to 140 characters or more, it will be truncate. - ```yaml template.app-deployed: | message: | Application {{.app.metadata.name}} is now running new version of deployments manifests. github: + repoURLPath: "{{.app.spec.source.repoURL}}" + revisionPath: "{{.app.status.operationState.syncResult.revision}}" status: state: success label: "continuous-delivery/{{.app.metadata.name}}" targetURL: "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" + deployment: + state: success + environment: production + environmentURL: "https://{{.app.metadata.name}}.example.com" + 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**: +- If the message is set to 140 characters or more, it will be truncated. +- 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). +- 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 ff567b71c1ee6..1f3e77701f044 100755 --- a/docs/operator-manual/notifications/services/grafana.md +++ b/docs/operator-manual/notifications/services/grafana.md @@ -4,6 +4,12 @@ To be able to create Grafana annotation with argocd-notifications you have to cr ![sample](https://user-images.githubusercontent.com/18019529/112024976-0f106080-8b78-11eb-9658-7663305899be.png) +Available parameters : + +* `apiURL` - the server url, e.g. https://grafana.example.com +* `apiKey` - the API key for the serviceaccount +* `insecureSkipVerify` - optional bool, true or false + 1. Login to your Grafana instance as `admin` 2. On the left menu, go to Configuration / API Keys 3. Click "Add API Key" @@ -15,7 +21,7 @@ To be able to create Grafana annotation with argocd-notifications you have to cr 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/overview.md b/docs/operator-manual/notifications/services/overview.md index 15e674f65412b..265e575755088 100755 --- a/docs/operator-manual/notifications/services/overview.md +++ b/docs/operator-manual/notifications/services/overview.md @@ -38,6 +38,7 @@ metadata: ## Service Types +* [AwsSqs](./awssqs.md) * [Email](./email.md) * [GitHub](./github.md) * [Slack](./slack.md) diff --git a/docs/operator-manual/notifications/services/pagerduty.md b/docs/operator-manual/notifications/services/pagerduty.md index 849b4db802d9d..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 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: "" -``` \ No newline at end of file + 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 new file mode 100755 index 0000000000000..549cdc937b150 --- /dev/null +++ b/docs/operator-manual/notifications/services/pagerduty_v2.md @@ -0,0 +1,78 @@ +# PagerDuty V2 + +## Parameters + +The PagerDuty notification service is used to trigger PagerDuty events and requires specifying the following settings: + +* `serviceKeys` - a dictionary with the following structure: + * `service-name: $pagerduty-key-service-name` where `service-name` is the name you want to use for the service to make events for, and `$pagerduty-key-service-name` is a reference to the secret that contains the actual PagerDuty integration key (Events API v2 integration) + +If you want multiple Argo apps to trigger events to their respective PagerDuty services, create an integration key in each service you want to setup alerts for. + +To create a PagerDuty integration key, [follow these instructions](https://support.pagerduty.com/docs/services-and-integrations#create-a-generic-events-api-integration) to add an Events API v2 integration to the service of your choice. + +## Configuration + +The following snippet contains sample PagerDuty service configuration. It assumes the service you want to alert on is called `my-service`. + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: +stringData: + pagerduty-key-my-service: +``` + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-notifications-cm +data: + service.pagerdutyv2: | + serviceKeys: + my-service: $pagerduty-key-my-service +``` + +## Template + +[Notification templates](../templates.md) support specifying subject for PagerDuty notifications: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-notifications-cm +data: + template.rollout-aborted: | + message: Rollout {{.rollout.metadata.name}} is aborted. + pagerdutyv2: + summary: "Rollout {{.rollout.metadata.name}} is aborted." + severity: "critical" + source: "{{.rollout.metadata.name}}" +``` + +The parameters for the PagerDuty configuration in the template generally match with the payload for the Events API v2 endpoint. All parameters are strings. + +* `summary` - (required) A brief text summary of the event, used to generate the summaries/titles of any associated alerts. +* `severity` - (required) The perceived severity of the status the event is describing with respect to the affected system. Allowed values: `critical`, `warning`, `error`, `info` +* `source` - (required) The unique location of the affected system, preferably a hostname or FQDN. +* `component` - Component of the source machine that is responsible for the event. +* `group` - Logical grouping of components of a service. +* `class` - The class/type of the event. +* `url` - The URL that should be used for the link "View in ArgoCD" in PagerDuty. + +The `timestamp` and `custom_details` parameters are not currently supported. + +## Annotation + +Annotation sample for PagerDuty notifications: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Rollout +metadata: + annotations: + 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 554f42a808f01..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 @@ -64,7 +64,7 @@ metadata: ## Templates -Notification templates can be customized with RocketChat [attachments](https://developer.rocket.chat/api/rest-api/methods/chat/postmessage#attachments-detail). +[Notification templates](../templates.md) can be customized with RocketChat [attachments](https://developer.rocket.chat/api/rest-api/methods/chat/postmessage#attachments-detail). *Note: Attachments structure in Rocketchat is same with Slack attachments [feature](https://api.slack.com/messaging/composing/layouts).* diff --git a/docs/operator-manual/notifications/services/slack.md b/docs/operator-manual/notifications/services/slack.md index 0cd9a0f17708e..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 @@ -29,60 +34,60 @@ The Slack notification service configuration includes following settings: 1. Invite your slack bot to this channel **otherwise slack bot won't be able to deliver notifications to this channel** 1. Store Oauth access token in `argocd-notifications-secret` secret -```yaml - apiVersion: v1 - kind: Secret - metadata: - name: - stringData: - slack-token: -``` + ```yaml + apiVersion: v1 + kind: Secret + metadata: + name: + stringData: + slack-token: + ``` 1. Define service type slack in data section of `argocd-notifications-cm` configmap: -```yaml - apiVersion: v1 - kind: ConfigMap - metadata: - name: - data: - service.slack: | - token: $slack-token -``` - -1. Add annotation in application yaml file to enable notifications for specific argocd app - -```yaml - apiVersion: argoproj.io/v1alpha1 - kind: Application - metadata: - annotations: - notifications.argoproj.io/subscribe.on-sync-succeeded.slack: my_channel -``` - -1. Annotation with more than one trigger multiple of destinations and recipients - -```yaml - apiVersion: argoproj.io/v1alpha1 - kind: Application - metadata: - annotations: - notifications.argoproj.io/subscriptions: | - - trigger: [on-scaling-replica-set, on-rollout-updated, on-rollout-step-completed] - destinations: - - service: slack - recipients: [my-channel-1, my-channel-2] - - service: email - recipients: [recipient-1, recipient-2, recipient-3 ] - - trigger: [on-rollout-aborted, on-analysis-run-failed, on-analysis-run-error] - destinations: - - service: slack - recipients: [my-channel-21, my-channel-22] -``` + ```yaml + apiVersion: v1 + kind: ConfigMap + metadata: + name: argocd-notifications-cm + data: + service.slack: | + token: $slack-token + ``` + +1. Add annotation in application yaml file to enable notifications for specific argocd app. The following example uses the [on-sync-succeeded trigger](../catalog.md#triggers): + + ```yaml + apiVersion: argoproj.io/v1alpha1 + kind: Application + metadata: + annotations: + notifications.argoproj.io/subscribe.on-sync-succeeded.slack: my_channel + ``` + +1. Annotation with more than one [trigger](../catalog.md#triggers), with multiple destinations and recipients + + ```yaml + apiVersion: argoproj.io/v1alpha1 + kind: Application + metadata: + annotations: + notifications.argoproj.io/subscriptions: | + - trigger: [on-scaling-replica-set, on-rollout-updated, on-rollout-step-completed] + destinations: + - service: slack + recipients: [my-channel-1, my-channel-2] + - service: email + recipients: [recipient-1, recipient-2, recipient-3 ] + - trigger: [on-rollout-aborted, on-analysis-run-failed, on-analysis-run-error] + destinations: + - service: slack + recipients: [my-channel-21, my-channel-22] + ``` ## Templates -Notification templates can be customized to leverage slack message blocks and attachments +[Notification templates](../templates.md) can be customized to leverage slack message blocks and attachments [feature](https://api.slack.com/messaging/composing/layouts). ![](https://user-images.githubusercontent.com/426437/72776856-6dcef880-3bc8-11ea-8e3b-c72df16ee8e6.png) diff --git a/docs/operator-manual/notifications/services/teams.md b/docs/operator-manual/notifications/services/teams.md index eb50f5538c8b6..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: @@ -48,7 +48,7 @@ metadata: ![](https://user-images.githubusercontent.com/18019529/114271500-9d2b8880-9a4c-11eb-85c1-f6935f0431d5.png) -Notification templates can be customized to leverage teams message sections, facts, themeColor, summary and potentialAction [feature](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using). +[Notification templates](../templates.md) can be customized to leverage teams message sections, facts, themeColor, summary and potentialAction [feature](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using). ```yaml template.app-sync-succeeded: | @@ -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) @@ -123,4 +123,4 @@ You can set a summary of the message that will be shown on Notifcation & Activit template.app-sync-succeeded: | teams: summary: "Sync Succeeded" -``` \ No newline at end of file +``` 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/subscriptions.md b/docs/operator-manual/notifications/subscriptions.md index 44c500ac16f4a..e9f985280f8ad 100644 --- a/docs/operator-manual/notifications/subscriptions.md +++ b/docs/operator-manual/notifications/subscriptions.md @@ -9,13 +9,13 @@ metadata: notifications.argoproj.io/subscribe.on-sync-succeeded.slack: my-channel1;my-channel2 ``` -Annotation key consists of following parts: +The annotation key consists of following parts: * `on-sync-succeeded` - trigger name * `slack` - notification service name * `my-channel1;my-channel2` - a semicolon separated list of recipients -You can create subscriptions for all applications of the Argo CD project by adding the same annotation to AppProject CRD: +You can create subscriptions for all applications of an Argo CD project by adding the same annotation to the AppProject resource: ```yaml apiVersion: argoproj.io/v1alpha1 @@ -27,7 +27,7 @@ metadata: ## Default Subscriptions -The subscriptions might be configured globally in the `argocd-notifications-cm` ConfigMap using `subscriptions` field. The default subscriptions +The subscriptions might be configured globally in the `argocd-notifications-cm` ConfigMap using the `subscriptions` field. The default subscriptions are applied to all applications. The trigger and applications might be configured using the `triggers` and `selector` fields: @@ -53,7 +53,7 @@ data: - on-sync-status-unknown ``` -If you want to use webhook in subscriptions, you need to store the custom name to recipients. +If you want to use webhook in subscriptions, you need to store the custom webhook name in the subscription's `recipients` field. ```yaml apiVersion: v1 diff --git a/docs/operator-manual/notifications/templates.md b/docs/operator-manual/notifications/templates.md index 972c62734f739..1d80f20953b24 100644 --- a/docs/operator-manual/notifications/templates.md +++ b/docs/operator-manual/notifications/templates.md @@ -1,5 +1,5 @@ -The notification template is used to generate the notification content and configured in `argocd-notifications-cm` ConfigMap. The template is leveraging -[html/template](https://golang.org/pkg/html/template/) golang package and allow to customize notification message. +The notification template is used to generate the notification content and is configured in the `argocd-notifications-cm` ConfigMap. The template is leveraging +the [html/template](https://golang.org/pkg/html/template/) golang package and allows customization of the notification message. Templates are meant to be reusable and can be referenced by multiple triggers. The following template is used to notify the user about application sync status. @@ -19,9 +19,10 @@ data: Each template has access to the following fields: - `app` holds the application object. -- `context` is user defined string map and might include any string keys and values. -- `serviceType` holds the notification service type name. The field can be used to conditionally -render service specific fields. +- `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. ## Defining user-defined `context` @@ -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 @@ -51,30 +85,30 @@ See corresponding service [documentation](services/overview.md) for more informa ## Change the timezone -You can change the timezone to show it as follows. +You can change the timezone to show in notifications as follows. 1. Call time functions. -``` -{{ (call .time.Parse .app.status.operationState.startedAt).Local.Format "2006-01-02T15:04:05Z07:00" }} -``` + ``` + {{ (call .time.Parse .app.status.operationState.startedAt).Local.Format "2006-01-02T15:04:05Z07:00" }} + ``` -2. Set environment to container. +2. Set the `TZ` environment variable on the argocd-notifications-controller container. -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: argocd-notifications-controller -spec: -(snip) + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: argocd-notifications-controller spec: - containers: - - name: argocd-notifications-controller - env: - - name: TZ - value: Asia/Tokyo -``` + template: + spec: + containers: + - name: argocd-notifications-controller + env: + - name: TZ + value: Asia/Tokyo + ``` ## Functions diff --git a/docs/operator-manual/notifications/triggers.md b/docs/operator-manual/notifications/triggers.md index aecaee81b80c6..49a6244777959 100644 --- a/docs/operator-manual/notifications/triggers.md +++ b/docs/operator-manual/notifications/triggers.md @@ -1,9 +1,9 @@ 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 `argocd-notifications-cm` ConfigMap. For example the following trigger sends a notification +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: ```yaml @@ -17,9 +17,9 @@ data: send: [app-sync-status, github-commit-status] # template names ``` -Each condition might use several templates. Typically each template is responsible for generating a service-specific notification part. -In the example above `app-sync-status` template "knows" how to create email and slack notification and `github-commit-status` knows how to -generate payload for Github webhook. +Each condition might use several templates. Typically, each template is responsible for generating a service-specific notification part. +In the example above, the `app-sync-status` template "knows" how to create email and Slack notification, and `github-commit-status` knows how to +generate the payload for GitHub webhook. ## Conditions Bundles @@ -28,7 +28,6 @@ The end users just need to subscribe to the trigger and specify the notification triggers might include multiple conditions with a different set of templates for each condition. For example, the following trigger covers all stages of sync status operation and use a different template for different cases: - ```yaml apiVersion: v1 kind: ConfigMap @@ -66,9 +65,13 @@ data: send: [app-sync-succeeded] ``` +**Mono Repo Usage** + +When one repo is used to sync multiple applications, the `oncePer: app.status.sync.revision` field will trigger a notification for each commit. For mono repos, the better approach will be using `oncePer: app.status.operationState.syncResult.revision` statement. This way a notification will be sent only for a particular Application's revision. + ### oncePer -The `oncePer` filed is supported like as follows. +The `oncePer` field is supported like as follows. ```yaml apiVersion: argoproj.io/v1alpha1 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/notifications/troubleshooting-errors.md b/docs/operator-manual/notifications/troubleshooting-errors.md index c46d4c47468e0..f76bb7a2b0d3f 100644 --- a/docs/operator-manual/notifications/troubleshooting-errors.md +++ b/docs/operator-manual/notifications/troubleshooting-errors.md @@ -36,6 +36,6 @@ You need to check your argocd-notifications controller version. For instance, th ## Failed to notify recipient -### notification service 'xxxx' is not supported" +### notification service 'xxxx' is not supported You have not defined `xxxx` in `argocd-notifications-cm` or to fail to parse settings. diff --git a/docs/operator-manual/notifications/troubleshooting.md b/docs/operator-manual/notifications/troubleshooting.md index 68ea134e0c52a..616cd4b024e82 100644 --- a/docs/operator-manual/notifications/troubleshooting.md +++ b/docs/operator-manual/notifications/troubleshooting.md @@ -1,32 +1,30 @@ -## Troubleshooting - -The `argocd admin notifications` is a CLI command group that helps to configure the controller -settings and troubleshoot issues. +`argocd admin notifications` is a CLI command group that helps to configure the controller +settings and troubleshoot issues. Full command details are available in the [command reference](../../user-guide/commands/argocd_admin_notifications.md). ## Global flags -Following global flags are available for all sub-commands: +The following global flags are available for all sub-commands: -* `config-map` - path to the file containing `argocd-notifications-cm` ConfigMap. If not specified +* `--config-map` - path to the file containing `argocd-notifications-cm` ConfigMap. If not specified then the command loads `argocd-notification-cm` ConfigMap using the local Kubernetes config file. -* `secret` - path to the file containing `argocd-notifications-secret` ConfigMap. If not +* `--secret` - path to the file containing `argocd-notifications-secret` ConfigMap. If not specified then the command loads `argocd-notification-secret` Secret using the local Kubernetes config file. -Additionally, you can specify `:empty` value to use empty secret with no notification service settings. +Additionally, you can specify `:empty` to use empty secret with no notification service settings. **Examples:** -* Get list of triggers configured in the local config map: +* Get a list of triggers configured in the local config map: -```bash -argocd admin notifications trigger get \ - --config-map ./argocd admin notifications-cm.yaml --secret :empty -``` + ```bash + argocd admin notifications trigger get \ + --config-map ./argocd-notifications-cm.yaml --secret :empty + ``` * Trigger notification using in-cluster config map and secret: -```bash -argocd admin notifications template notify \ - app-sync-succeeded guestbook --recipient slack:argocd admin notifications -``` + ```bash + argocd admin notifications template notify \ + app-sync-succeeded guestbook --recipient slack:argocd admin notifications + ``` ## Kustomize @@ -44,17 +42,17 @@ kustomize build ./argocd-notifications | \ ### On your laptop -You can download the `argocd` CLI from the github [release](https://github.com/argoproj/argo-cd/releases) +You can download the `argocd` CLI from the GitHub [release](https://github.com/argoproj/argo-cd/releases) attachments. -The binary is available in `argoproj/argo-cd` image. Use the `docker run` and volume mount +The binary is available in the `quay.io/argoproj/argocd` image. Use the `docker run` and volume mount to execute binary on any platform. **Example:** ```bash docker run --rm -it -w /src -v $(pwd):/src \ - argoproj/argo-cd: \ + quay.io/argoproj/argocd: \ /app/argocd admin notifications trigger get \ --config-map ./argocd-notifications-cm.yaml --secret :empty ``` @@ -72,7 +70,12 @@ kubectl exec -it argocd-notifications-controller- \ ## Commands -{!docs/operator-manual/notifications/troubleshooting-commands.md!} +The following commands may help debug issues with notifications: + +* [`argocd admin notifications template get`](../../user-guide/commands/argocd_admin_notifications_template_get.md) +* [`argocd admin notifications template notify`](../../user-guide/commands/argocd_admin_notifications_template_notify.md) +* [`argocd admin notifications trigger get`](../../user-guide/commands/argocd_admin_notifications_trigger_get.md) +* [`argocd admin notifications trigger run`](../../user-guide/commands/argocd_admin_notifications_trigger_run.md) ## Errors diff --git a/docs/operator-manual/project-specification.md b/docs/operator-manual/project-specification.md new file mode 100644 index 0000000000000..4d18eb1a9dd1b --- /dev/null +++ b/docs/operator-manual/project-specification.md @@ -0,0 +1,7 @@ +# Project Specification + +The following describes all the available fields of a Project: + +```yaml +{!docs/operator-manual/project.yaml!} +``` diff --git a/docs/operator-manual/project.yaml b/docs/operator-manual/project.yaml index 20dcfa87ab29c..c4d93f536239f 100644 --- a/docs/operator-manual/project.yaml +++ b/docs/operator-manual/project.yaml @@ -86,3 +86,13 @@ spec: clusters: - in-cluster - cluster1 + + # By default, apps may sync to any cluster specified under the `destinations` field, even if they are not + # scoped to this project. Set the following field to `true` to restrict apps in this cluster to only clusters + # scoped to this project. + permitOnlyProjectScopedClusters: false + + # When using Applications-in-any-namespace, this field determines which namespaces this AppProject permits + # Applications to reside in. Details: https://argo-cd.readthedocs.io/en/stable/operator-manual/app-any-namespace/ + sourceNamespaces: + - "argocd-apps-*" diff --git a/docs/operator-manual/rbac.md b/docs/operator-manual/rbac.md index fac03e4b2f744..b1d386fb5eb8e 100644 --- a/docs/operator-manual/rbac.md +++ b/docs/operator-manual/rbac.md @@ -2,7 +2,7 @@ The RBAC feature enables restriction of access to Argo CD resources. Argo CD does not have its own user management system and has only one built-in user `admin`. The `admin` user is a superuser and -it has unrestricted access to the system. RBAC requires [SSO configuration](user-management/index.md) or [one or more local users setup](user-management/index.md). +it has unrestricted access to the system. RBAC requires [SSO configuration](user-management/index.md) or [one or more local users setup](user-management/index.md). Once SSO or local users are configured, additional RBAC roles can be defined, and SSO groups or local users can then be mapped to roles. ## Basic Built-in Roles @@ -22,13 +22,15 @@ Breaking down the permissions definition differs slightly between applications a `p, , , , ` -* Applications, applicationsets, logs, and exec (which belong to an AppProject): +* Applications, applicationsets, logs, and exec (which belong to an `AppProject`): `p, , , , /` ### RBAC Resources and Actions -Resources: `clusters`, `projects`, `applications`, `applicationsets`, `repositories`, `certificates`, `accounts`, `gpgkeys`, `logs`, `exec` +Resources: `clusters`, `projects`, `applications`, `applicationsets`, +`repositories`, `certificates`, `accounts`, `gpgkeys`, `logs`, `exec`, +`extensions` Actions: `get`, `create`, `update`, `delete`, `sync`, `override`,`action/` @@ -55,18 +57,25 @@ corresponds to the `action` path `action/extensions/DaemonSet/restart`. You can also use glob patterns in the action path: `action/*` (or regex patterns if you have [enabled the `regex` match mode](https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/argocd-rbac-cm.yaml)). +If the resource is not under a group (for examples, Pods or ConfigMaps), then omit the group name from your RBAC +configuration: + +```csv +p, example-user, applications, action//Pod/maintenance-off, default/*, allow +``` + #### The `exec` resource -`exec` is a special resource. When enabled with the `create` action, this privilege allows a user to `exec` into Pods via +`exec` is a special resource. When enabled with the `create` action, this privilege allows a user to `exec` into Pods via the Argo CD UI. The functionality is similar to `kubectl exec`. See [Web-based Terminal](web_based_terminal.md) for more info. #### The `applicationsets` resource -[ApplicationSets](applicationset) provide a declarative way to automatically create/update/delete Applications. +[ApplicationSets](applicationset/index.md) provide a declarative way to automatically create/update/delete Applications. -Granting `applicationsets, create` effectively grants the ability to create Applications. While it doesn't allow the +Granting `applicationsets, create` effectively grants the ability to create Applications. While it doesn't allow the user to create Applications directly, they can create Applications via an ApplicationSet. In v2.5, it is not possible to create an ApplicationSet with a templated Project field (e.g. `project: {{path.basename}}`) @@ -79,6 +88,40 @@ p, dev-group, applicationsets, *, dev-project/*, allow With this rule in place, a `dev-group` user will be unable to create an ApplicationSet capable of creating Applications outside the `dev-project` project. +#### The `extensions` resource + +With the `extensions` resource it is possible configure permissions to +invoke [proxy +extensions](../developer-guide/extensions/proxy-extensions.md). The +`extensions` RBAC validation works in conjunction with the +`applications` resource. A user logged in Argo CD (UI or CLI), needs +to have at least read permission on the project, namespace and +application where the request is originated from. + +Consider the example below: + +```csv +g, ext, role:extension +p, role:extension, applications, get, default/httpbin-app, allow +p, role:extension, extensions, invoke, httpbin, allow +``` + +Explanation: + +* *line1*: defines the group `role:extension` associated with the + subject `ext`. +* *line2*: defines a policy allowing this role to read (`get`) the + `httpbin-app` application in the `default` project. +* *line3*: defines another policy allowing this role to `invoke` the + `httpbin` extension. + +**Note 1**: that for extensions requests to be allowed, the policy defined +in the *line2* is also required. + +**Note 2**: `invoke` is a new action introduced specifically to be used +with the `extensions` resource. The current actions for `extensions` +are `*` or `invoke`. + ## Tying It All Together Additional roles and groups can be configured in `argocd-rbac-cm` ConfigMap. The example below @@ -87,7 +130,7 @@ configures a custom role, named `org-admin`. The role is assigned to any user wh which cannot modify Argo CD settings. !!! warning - All authenticated users get _at least_ the permissions granted by the default policy. This access cannot be blocked + All authenticated users get *at least* the permissions granted by the default policy. This access cannot be blocked by a `deny` rule. Instead, restrict the default policy and then grant permissions to individual roles as needed. *ArgoCD ConfigMap `argocd-rbac-cm` Example:* @@ -107,29 +150,96 @@ data: p, role:org-admin, repositories, create, *, allow p, role:org-admin, repositories, update, *, allow p, role:org-admin, repositories, delete, *, allow + p, role:org-admin, projects, get, *, allow + p, role:org-admin, projects, create, *, allow + p, role:org-admin, projects, update, *, allow + p, role:org-admin, projects, delete, *, allow p, role:org-admin, logs, get, *, allow p, role:org-admin, exec, create, */*, allow g, your-github-org:your-team, role:org-admin ``` + ---- Another `policy.csv` example might look as follows: ```csv -p, role:staging-db-admins, applications, create, staging-db-admins/*, allow -p, role:staging-db-admins, applications, delete, staging-db-admins/*, allow -p, role:staging-db-admins, applications, get, staging-db-admins/*, allow -p, role:staging-db-admins, applications, override, staging-db-admins/*, allow -p, role:staging-db-admins, applications, sync, staging-db-admins/*, allow -p, role:staging-db-admins, applications, update, staging-db-admins/*, allow -p, role:staging-db-admins, logs, get, staging-db-admins/*, allow -p, role:staging-db-admins, exec, create, staging-db-admins/*, allow -p, role:staging-db-admins, projects, get, staging-db-admins, allow -g, db-admins, role:staging-db-admins +p, role:staging-db-admin, applications, create, staging-db-project/*, allow +p, role:staging-db-admin, applications, delete, staging-db-project/*, allow +p, role:staging-db-admin, applications, get, staging-db-project/*, allow +p, role:staging-db-admin, applications, override, staging-db-project/*, allow +p, role:staging-db-admin, applications, sync, staging-db-project/*, allow +p, role:staging-db-admin, applications, update, staging-db-project/*, allow +p, role:staging-db-admin, logs, get, staging-db-project/*, allow +p, role:staging-db-admin, exec, create, staging-db-project/*, allow +p, role:staging-db-admin, projects, get, staging-db-project, allow +g, db-admins, role:staging-db-admin ``` -This example defines a *role* called `staging-db-admins` with *nine permissions* that allow that role to perform the *actions* (`create`/`delete`/`get`/`override`/`sync`/`update` applications, `get` logs, `create` exec and `get` appprojects) against `*` (all) objects in the `staging-db-admins` Argo CD AppProject. +This example defines a *role* called `staging-db-admin` with nine *permissions* that allow users with that role to perform the following *actions*: + +* `create`, `delete`, `get`, `override`, `sync` and `update` for applications in the `staging-db-project` project, +* `get` logs for objects in the `staging-db-project` project, +* `create` exec for objects in the `staging-db-project` project, and +* `get` for the project named `staging-db-project`. + +!!! note + The `scopes` field controls which OIDC scopes to examine during rbac + enforcement (in addition to `sub` scope). If omitted, defaults to: + `'[groups]'`. The scope value can be a string, or a list of strings. + +Following example shows targeting `email` as well as `groups` from your OIDC provider. + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-rbac-cm + namespace: argocd + labels: + app.kubernetes.io/name: argocd-rbac-cm + app.kubernetes.io/part-of: argocd +data: + policy.csv: | + p, my-org:team-alpha, applications, sync, my-project/*, allow + g, my-org:team-beta, role:admin + g, user@example.org, role:admin + policy.default: role:readonly + scopes: '[groups, email]' +``` + +For more information on `scopes` please review the [User Management Documentation](user-management/index.md). + +## Policy CSV Composition + +It is possible to provide additional entries in the `argocd-rbac-cm` +configmap to compose the final policy csv. In this case the key must +follow the pattern `policy..csv`. Argo CD will concatenate +all additional policies it finds with this pattern below the main one +('policy.csv'). The order of additional provided policies are +determined by the key string. Example: if two additional policies are +provided with keys `policy.A.csv` and `policy.B.csv`, it will first +concatenate `policy.A.csv` and then `policy.B.csv`. + +This is useful to allow composing policies in config management tools +like Kustomize, Helm, etc. + +The example below shows how a Kustomize patch can be provided in an +overlay to add additional configuration to an existing RBAC policy. + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-rbac-cm + namespace: argocd +data: + policy.tester-overlay.csv: | + p, role:tester, applications, *, */*, allow + p, role:tester, projects, *, *, allow + g, my-org:team-qa, role:tester +``` ## Anonymous Access @@ -184,38 +294,43 @@ Given the example from the above ConfigMap, which defines the role `role:org-admin`, and is stored on your local system as `argocd-rbac-cm-yaml`, you can test whether that role can do something like follows: -```shell +```console $ argocd admin settings rbac can role:org-admin get applications --policy-file argocd-rbac-cm.yaml Yes + $ argocd admin settings rbac can role:org-admin get clusters --policy-file argocd-rbac-cm.yaml Yes + $ argocd admin settings rbac can role:org-admin create clusters 'somecluster' --policy-file argocd-rbac-cm.yaml No + $ argocd admin settings rbac can role:org-admin create applications 'someproj/someapp' --policy-file argocd-rbac-cm.yaml Yes ``` Another example, given the policy above from `policy.csv`, which defines the -role `role:staging-db-admins` and associates the group `db-admins` with it. +role `role:staging-db-admin` and associates the group `db-admins` with it. Policy is stored locally as `policy.csv`: You can test against the role: -```shell -# Plain policy, without a default role defined -$ argocd admin settings rbac can role:staging-db-admins get applications --policy-file policy.csv +```console +$ # Plain policy, without a default role defined +$ argocd admin settings rbac can role:staging-db-admin get applications --policy-file policy.csv No -$ argocd admin settings rbac can role:staging-db-admins get applications 'staging-db-admins/*' --policy-file policy.csv + +$ argocd admin settings rbac can role:staging-db-admin get applications 'staging-db-project/*' --policy-file policy.csv Yes -# Argo CD augments a builtin policy with two roles defined, the default role -# being 'role:readonly' - You can include a named default role to use: -$ argocd admin settings rbac can role:staging-db-admins get applications --policy-file policy.csv --default-role role:readonly + +$ # Argo CD augments a builtin policy with two roles defined, the default role +$ # being 'role:readonly' - You can include a named default role to use: +$ argocd admin settings rbac can role:staging-db-admin get applications --policy-file policy.csv --default-role role:readonly Yes ``` Or against the group defined: -```shell -$ argocd admin settings rbac can db-admins get applications 'staging-db-admins/*' --policy-file policy.csv +```console +$ argocd admin settings rbac can db-admins get applications 'staging-db-project/*' --policy-file policy.csv Yes ``` diff --git a/docs/operator-manual/reconcile.md b/docs/operator-manual/reconcile.md new file mode 100644 index 0000000000000..a956cd9cf7b28 --- /dev/null +++ b/docs/operator-manual/reconcile.md @@ -0,0 +1,113 @@ +# Reconcile Optimization + +By default, an Argo CD Application is refreshed every time a resource that belongs to it changes. + +Kubernetes controllers often update the resources they watch periodically, causing continuous reconcile operation on the Application +and a high CPU usage on the `argocd-application-controller`. Argo CD allows you to optionally ignore resource updates on specific fields +for [tracked resources](../user-guide/resource_tracking.md). + +When a resource update is ignored, if the resource's [health status](./health.md) does not change, the Application that this resource belongs to will not be reconciled. + +## System-Level Configuration + +Argo CD allows ignoring resource updates at a specific JSON path, using [RFC6902 JSON patches](https://tools.ietf.org/html/rfc6902) and [JQ path expressions](https://stedolan.github.io/jq/manual/#path(path_expression)). It can be configured for a specified group and kind +in `resource.customizations` key of the `argocd-cm` ConfigMap. + +!!!important "Enabling the feature" + The feature is behind a flag. To enable it, set `resource.ignoreResourceUpdatesEnabled` to `"true"` in the `argocd-cm` ConfigMap. + +Following is an example of a customization which ignores the `refreshTime` status field of an [`ExternalSecret`](https://external-secrets.io/main/api/externalsecret/) resource: + +```yaml +data: + resource.customizations.ignoreResourceUpdates.external-secrets.io_ExternalSecret: | + jsonPointers: + - /status/refreshTime + # JQ equivalent of the above: + # jqPathExpressions: + # - .status.refreshTime +``` + +It is possible to configure `ignoreResourceUpdates` to be applied to all tracked resources in every Application managed by an Argo CD instance. In order to do so, resource customizations can be configured like in the example below: + +```yaml +data: + resource.customizations.ignoreResourceUpdates.all: | + jsonPointers: + - /status +``` + +### Using ignoreDifferences to ignore reconcile + +It is possible to use existing system-level `ignoreDifferences` customizations to ignore resource updates as well. Instead of copying all configurations, +the `ignoreDifferencesOnResourceUpdates` setting can be used to add all ignored differences as ignored resource updates: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cm +data: + resource.compareoptions: | + ignoreDifferencesOnResourceUpdates: true +``` + +## Default Configuration + +By default, the metadata fields `generation`, `resourceVersion` and `managedFields` are always ignored for all resources. + +## Finding Resources to Ignore + +The application controller logs when a resource change triggers a refresh. You can use these logs to find +high-churn resource kinds and then inspect those resources to find which fields to ignore. + +To find these logs, search for `"Requesting app refresh caused by object update"`. The logs include structured +fields for `api-version` and `kind`. Counting the number of refreshes triggered, by api-version/kind should +reveal the high-churn resource kinds. + +!!!note + These logs are at the `debug` level. Configure the application-controller's log level to `debug`. + +Once you have identified some resources which change often, you can try to determine which fields are changing. Here is +one approach: + +```shell +kubectl get -o yaml > /tmp/before.yaml +# Wait a minute or two. +kubectl get -o yaml > /tmp/after.yaml +diff /tmp/before.yaml /tmp/after +``` + +The diff can give you a sense for which fields are changing and should perhaps be ignored. + +## Checking Whether Resource Updates are Ignored + +Whenever Argo CD skips a refresh due to an ignored resource update, the controller logs the following line: +"Ignoring change of object because none of the watched resource fields have changed". + +Search the application-controller logs for this line to confirm that your resource ignore rules are being applied. + +!!!note + These logs are at the `debug` level. Configure the application-controller's log level to `debug`. + +## Examples + +### argoproj.io/Application + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cm +data: + resource.customizations.ignoreResourceUpdates.argoproj.io_Application: | + jsonPointers: + # Ignore when ownerReferences change, for example when a parent ApplicationSet changes often. + - /metadata/ownerReferences + # Ignore reconciledAt, since by itself it doesn't indicate any important change. + - /status/reconciledAt + jqPathExpressions: + # Ignore lastTransitionTime for conditions; helpful when SharedResourceWarnings are being regularly updated but not + # actually changing in content. + - .status.conditions[].lastTransitionTime +``` diff --git a/docs/operator-manual/resource_actions.md b/docs/operator-manual/resource_actions.md index 833eef4ffa534..b720f589ae8d0 100644 --- a/docs/operator-manual/resource_actions.md +++ b/docs/operator-manual/resource_actions.md @@ -9,15 +9,33 @@ Operators can add actions to custom resources in form of a Lua script and expand Argo CD supports custom resource actions written in [Lua](https://www.lua.org/). This is useful if you: - * Have a custom resource for which Argo CD does not provide any built-in actions. - * Have a commonly performed manual task that might be error prone if executed by users via `kubectl` +* Have a custom resource for which Argo CD does not provide any built-in actions. +* Have a commonly performed manual task that might be error prone if executed by users via `kubectl` +The resource actions act on a single object. You can define your own custom resource actions in the `argocd-cm` ConfigMap. +### Custom Resource Action Types + +#### An action that modifies the source resource + +This action modifies and returns the source resource. +This kind of action was the only one available till 2.8, and it is still supported. + +#### An action that produces a list of new or modified resources + +**An alpha feature, introduced in 2.8.** + +This action returns a list of impacted resources, each impacted resource has a K8S resource and an operation to perform on. +Currently supported operations are "create" and "patch", "patch" is only supported for the source resource. +Creating new resources is possible, by specifying a "create" operation for each such resource in the returned list. +One of the returned resources can be the modified source object, with a "patch" operation, if needed. +See the definition examples below. + ### Define a Custom Resource Action in `argocd-cm` ConfigMap -Custom resource actions can be defined in `resource.customizations.actions.` field of `argocd-cm`. Following example demonstrates a set of custom actions for `CronJob` resources. +Custom resource actions can be defined in `resource.customizations.actions.` field of `argocd-cm`. Following example demonstrates a set of custom actions for `CronJob` resources, each such action returns the modified CronJob. The customizations key is in the format of `resource.customizations.actions.`. ```yaml @@ -52,4 +70,114 @@ resource.customizations.actions.batch_CronJob: | The `discovery.lua` script must return a table where the key name represents the action name. You can optionally include logic to enable or disable certain actions based on the current object state. -Each action name must be represented in the list of `definitions` with an accompanying `action.lua` script to control the resource modifications. The `obj` is a global variable which contains the resource. Each action script must return an optionally modified version of the resource. In this example, we are simply setting `.spec.suspend` to either `true` or `false`. +Each action name must be represented in the list of `definitions` with an accompanying `action.lua` script to control the resource modifications. The `obj` is a global variable which contains the resource. Each action script returns an optionally modified version of the resource. In this example, we are simply setting `.spec.suspend` to either `true` or `false`. + +#### Creating new resources with a custom action + +!!! important + Creating resources via the Argo CD UI is an intentional, strategic departure from GitOps principles. We recommend + that you use this feature sparingly and only for resources that are not part of the desired state of the + application. + +The resource the action is invoked on would be referred to as the `source resource`. +The new resource and all the resources implicitly created as a result, must be permitted on the AppProject level, otherwise the creation will fail. + +##### Creating a source resource child resources with a custom action + +If the new resource represents a k8s child of the source resource, the source resource ownerReference must be set on the new resource. +Here is an example Lua snippet, that takes care of constructing a Job resource that is a child of a source CronJob resource - the `obj` is a global variable, which contains the source resource: + +```lua +-- ... +ownerRef = {} +ownerRef.apiVersion = obj.apiVersion +ownerRef.kind = obj.kind +ownerRef.name = obj.metadata.name +ownerRef.uid = obj.metadata.uid +job = {} +job.metadata = {} +job.metadata.ownerReferences = {} +job.metadata.ownerReferences[1] = ownerRef +-- ... +``` + +##### Creating independent child resources with a custom action + +If the new resource is independent of the source resource, the default behavior of such new resource is that it is not known by the App of the source resource (as it is not part of the desired state and does not have an `ownerReference`). +To make the App aware of the new resource, the `app.kubernetes.io/instance` label (or other ArgoCD tracking label, if configured) must be set on the resource. +It can be copied from the source resource, like this: + +```lua +-- ... +newObj = {} +newObj.metadata = {} +newObj.metadata.labels = {} +newObj.metadata.labels["app.kubernetes.io/instance"] = obj.metadata.labels["app.kubernetes.io/instance"] +-- ... +``` + +While the new resource will be part of the App with the tracking label in place, it will be immediately deleted if auto prune is set on the App. +To keep the resource, set `Prune=false` annotation on the resource, with this Lua snippet: + +```lua +-- ... +newObj.metadata.annotations = {} +newObj.metadata.annotations["argocd.argoproj.io/sync-options"] = "Prune=false" +-- ... +``` + +(If setting `Prune=false` behavior, the resource will not be deleted upon the deletion of the App, and will require a manual cleanup). + +The resource and the App will now appear out of sync - which is the expected ArgoCD behavior upon creating a resource that is not part of the desired state. + +If you wish to treat such an App as a synced one, add the following resource annotation in Lua code: + +```lua +-- ... +newObj.metadata.annotations["argocd.argoproj.io/compare-options"] = "IgnoreExtraneous" +-- ... +``` + +#### An action that produces a list of resources - a complete example: + +```yaml +resource.customizations.actions.ConfigMap: | + discovery.lua: | + actions = {} + actions["do-things"] = {} + return actions + definitions: + - name: do-things + action.lua: | + -- Create a new ConfigMap + cm1 = {} + cm1.apiVersion = "v1" + cm1.kind = "ConfigMap" + cm1.metadata = {} + cm1.metadata.name = "cm1" + cm1.metadata.namespace = obj.metadata.namespace + cm1.metadata.labels = {} + -- Copy ArgoCD tracking label so that the resource is recognized by the App + cm1.metadata.labels["app.kubernetes.io/instance"] = obj.metadata.labels["app.kubernetes.io/instance"] + cm1.metadata.annotations = {} + -- For Apps with auto-prune, set the prune false on the resource, so it does not get deleted + cm1.metadata.annotations["argocd.argoproj.io/sync-options"] = "Prune=false" + -- Keep the App synced even though it has a resource that is not in Git + cm1.metadata.annotations["argocd.argoproj.io/compare-options"] = "IgnoreExtraneous" + cm1.data = {} + cm1.data.myKey1 = "myValue1" + impactedResource1 = {} + impactedResource1.operation = "create" + impactedResource1.resource = cm1 + + -- Patch the original cm + obj.metadata.labels["aKey"] = "aValue" + impactedResource2 = {} + impactedResource2.operation = "patch" + impactedResource2.resource = obj + + result = {} + result[1] = impactedResource1 + result[2] = impactedResource2 + return result +``` \ No newline at end of file diff --git a/docs/operator-manual/secret-management.md b/docs/operator-manual/secret-management.md index 54795fe4cc56c..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) -* [Banzai Cloud Bank-Vaults](https://github.com/banzaicloud/bank-vaults) +* [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) @@ -18,6 +18,7 @@ Here are some ways people are doing GitOps secrets: * [argocd-vault-plugin](https://github.com/argoproj-labs/argocd-vault-plugin) * [argocd-vault-replacer](https://github.com/crumbhole/argocd-vault-replacer) * [Kubernetes Secrets Store CSI Driver](https://github.com/kubernetes-sigs/secrets-store-csi-driver) +* [Vals-Operator](https://github.com/digitalis-io/vals-operator) For discussion, see [#1364](https://github.com/argoproj/argo-cd/issues/1364) diff --git a/docs/operator-manual/security.md b/docs/operator-manual/security.md index 593030e1756e4..9d05c45cb7c74 100644 --- a/docs/operator-manual/security.md +++ b/docs/operator-manual/security.md @@ -30,7 +30,7 @@ in one of the following ways: ## Authorization Authorization is performed by iterating the list of group membership in a user's JWT groups claims, -and comparing each group against the roles/rules in the [RBAC](../rbac) policy. Any matched rule +and comparing each group against the roles/rules in the [RBAC](./rbac.md) policy. Any matched rule permits access to the API request. ## TLS @@ -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: @@ -144,7 +144,7 @@ argocd cluster rm https://your-kubernetes-cluster-addr ## Cluster RBAC -By default, Argo CD uses a [clusteradmin level role](https://github.com/argoproj/argo-cd/blob/master/manifests/base/application-controller/argocd-application-controller-role.yaml) +By default, Argo CD uses a [clusteradmin level role](https://github.com/argoproj/argo-cd/blob/master/manifests/base/application-controller-roles/argocd-application-controller-role.yaml) in order to: 1. watch & operate on cluster state @@ -173,7 +173,7 @@ kubectl edit clusterrole argocd-application-controller ``` !!! tip - If you want to deny ArgoCD access to a kind of resource then add it as an [excluded resource](declarative-setup.md#resource-exclusion). + If you want to deny Argo CD access to a kind of resource then add it as an [excluded resource](declarative-setup.md#resource-exclusion). ## Auditing diff --git a/docs/operator-manual/server-commands/argocd-application-controller.md b/docs/operator-manual/server-commands/argocd-application-controller.md index 85145b5540ef2..61c0c32119895 100644 --- a/docs/operator-manual/server-commands/argocd-application-controller.md +++ b/docs/operator-manual/server-commands/argocd-application-controller.md @@ -1,3 +1,5 @@ +# `argocd-application-controller` Command Reference + ## argocd-application-controller Run ArgoCD Application Controller @@ -13,56 +15,71 @@ argocd-application-controller [flags] ### Options ``` - --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-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 - --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 - --default-cache-expiration duration Cache expiration default (default 24h0m0s) - --gloglevel int Set the glog logging level - -h, --help help for argocd-application-controller - --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 - --kubectl-parallelism-limit int Number of allowed concurrent kubectl fork/execs. Any value less the 1 means no limit. (default 20) - --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") - --metrics-application-labels strings List of Application labels that will be added to the argocd_application_labels metric - --metrics-cache-expiration duration Prometheus metrics cache expiration (disabled by default. e.g. 24h0m0s) - --metrics-port int Start metrics server on given port (default 8082) - -n, --namespace string If present, the namespace scope for this CLI request - --operation-processors int Number of application operation processors (default 10) - --otlp-address string OpenTelemetry collector address to send traces to - --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 - --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: none, gzip) (default "none") - --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 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 - --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") - --self-heal-timeout-seconds int Specifies timeout between application self heal attempts (default 5) - --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 - --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 + --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 + --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 + --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 + --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 + --kubectl-parallelism-limit int Number of allowed concurrent kubectl fork/execs. Any value less than 1 means no limit. (default 20) + --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") + --metrics-application-labels strings List of Application labels that will be added to the argocd_application_labels metric + --metrics-cache-expiration duration Prometheus metrics cache expiration (disabled by default. e.g. 24h0m0s) + --metrics-port int Start metrics server on given port (default 8082) + -n, --namespace string If present, the namespace scope for this CLI request + --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 + --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-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 + --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") + --self-heal-timeout-seconds int Specifies timeout between application self heal attempts (default 5) + --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 float Set Workqueue Rate Limiter Bucket QPS, default set to MaxFloat64 which disables the bucket limiter (default 1.7976931348623157e+308) + --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.md b/docs/operator-manual/server-commands/argocd-dex.md index 89a53d4c31b56..af0eeae4a7604 100644 --- a/docs/operator-manual/server-commands/argocd-dex.md +++ b/docs/operator-manual/server-commands/argocd-dex.md @@ -1,3 +1,5 @@ +# `argocd-dex` Command Reference + ## argocd-dex argocd-dex tools used by Argo CD diff --git a/docs/operator-manual/server-commands/argocd-dex_gendexcfg.md b/docs/operator-manual/server-commands/argocd-dex_gendexcfg.md index 02118d2deef6e..a889b64133a93 100644 --- a/docs/operator-manual/server-commands/argocd-dex_gendexcfg.md +++ b/docs/operator-manual/server-commands/argocd-dex_gendexcfg.md @@ -1,3 +1,5 @@ +# `argocd-dex gendexcfg` Command Reference + ## argocd-dex gendexcfg Generates a dex config from Argo CD settings @@ -17,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 d4c25963e9196..b2d453feba613 100644 --- a/docs/operator-manual/server-commands/argocd-dex_rundex.md +++ b/docs/operator-manual/server-commands/argocd-dex_rundex.md @@ -1,3 +1,5 @@ +# `argocd-dex rundex` Command Reference + ## argocd-dex rundex Runs dex generating a config using settings from the Argo CD configmap and secret @@ -17,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 322886acbba50..0f824f494f2af 100644 --- a/docs/operator-manual/server-commands/argocd-repo-server.md +++ b/docs/operator-manual/server-commands/argocd-repo-server.md @@ -1,3 +1,5 @@ +# `argocd-repo-server` Command Reference + ## argocd-repo-server Run ArgoCD Repository Server @@ -13,15 +15,23 @@ argocd-repo-server [flags] ### Options ``` + --address string Listen on given address for incoming connections (default "0.0.0.0") --allow-oob-symlinks Allow out-of-bounds symlinks in repositories (not recommended) --default-cache-expiration duration Cache expiration default (default 24h0m0s) + --disable-helm-manifest-max-extracted-size Disable maximum size of helm manifest archives when extracted --disable-tls Disable TLS on the gRPC endpoint + --helm-manifest-max-extracted-size string Maximum size of helm manifest archives when extracted (default "1G") + --helm-registry-max-index-size string Maximum size of registry index file (default "1G") -h, --help help for argocd-repo-server --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") --max-combined-directory-manifests-size string Max combined size of manifest files in a directory-type Application (default "10M") + --metrics-address string Listen on given address for metrics (default "0.0.0.0") --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) @@ -29,12 +39,13 @@ argocd-repo-server [flags] --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: none, gzip) (default "none") + --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) --revision-cache-expiration duration Cache expiration for cached revision (default 3m0s) + --revision-cache-lock-timeout duration Cache TTL for locks to prevent duplicate requests on revisions, set to 0 to disable (default 10s) --sentinel stringArray Redis sentinel hostname and port (e.g. argocd-redis-ha-announce-0:6379). --sentinelmaster string Redis sentinel master group name. (default "master") --streamed-manifest-max-extracted-size string Maximum size of streamed manifest archives when extracted (default "1G") diff --git a/docs/operator-manual/server-commands/argocd-server.md b/docs/operator-manual/server-commands/argocd-server.md index 461ac194fa341..659a19de3d3e1 100644 --- a/docs/operator-manual/server-commands/argocd-server.md +++ b/docs/operator-manual/server-commands/argocd-server.md @@ -1,3 +1,5 @@ +# `argocd-server` Command Reference + ## argocd-server Run the ArgoCD API server @@ -10,70 +12,101 @@ 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 ``` - --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 - --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-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 - --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: none, gzip) (default "none") - --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) + --revision-cache-lock-timeout duration Cache TTL for locks to prevent duplicate requests on revisions, set to 0 to disable (default 10s) + --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 413ea6be9c3f3..2659c99e87219 100644 --- a/docs/operator-manual/server-commands/argocd-server_version.md +++ b/docs/operator-manual/server-commands/argocd-server_version.md @@ -1,3 +1,5 @@ +# `argocd-server version` Command Reference + ## argocd-server version Print version information @@ -24,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 d5aa36dc9eea1..b574876345b5b 100644 --- a/docs/operator-manual/signed-release-assets.md +++ b/docs/operator-manual/signed-release-assets.md @@ -1,31 +1,156 @@ -# Verification of Argo CD signatures - -All Argo CD container images are signed by cosign. Checksums are created for the CLI binaries and then signed to ensure integrity. +# Verification of Argo CD Artifacts ## Prerequisites -- Cosign [installation instructions](https://docs.sigstore.dev/cosign/installation) -- Obtain or have a copy of ```argocd-cosign.pub```, which can be located in the assets section of the [release page](https://github.com/argoproj/argo-cd/releases) - -Once you have installed cosign, you can use ```argocd-cosign.pub``` to verify the signed assets or container images. +- cosign `v2.0.0` or higher [installation instructions](https://docs.sigstore.dev/cosign/installation) +- slsa-verifier [installation instructions](https://github.com/slsa-framework/slsa-verifier#installation) +- crane [installation instructions](https://github.com/google/go-containerregistry/blob/main/cmd/crane/README.md) (for container verification only) +*** +## Release Assets +| Asset | Description | +|--------------------------|-------------------------------| +| argocd-darwin-amd64 | CLI Binary | +| argocd-darwin-arm64 | CLI Binary | +| argocd-linux_amd64 | CLI Binary | +| argocd-linux_arm64 | CLI Binary | +| argocd-linux_ppc64le | CLI Binary | +| argocd-linux_s390x | CLI Binary | +| argocd-windows_amd64 | CLI Binary | +| argocd-cli.intoto.jsonl | Attestation of CLI binaries | +| argocd-sbom.intoto.jsonl | Attestation of SBOM | +| cli_checksums.txt | Checksums of binaries | +| sbom.tar.gz | Sbom | +| sbom.tar.gz.pem | Certificate used to sign sbom | +| sbom.tar.gz.sig | Signature of sbom | +*** ## Verification of container images -```bash -cosign verify --key argocd-cosign.pub quay.io/argoproj/argocd: +Argo CD container images are signed by [cosign](https://github.com/sigstore/cosign) using identity-based ("keyless") signing and transparency. Executing the following command can be used to verify the signature of a container image: -Verification for quay.io/argoproj/argocd: -- +```bash +cosign verify \ +--certificate-identity-regexp https://github.com/argoproj/argo-cd/.github/workflows/image-reuse.yaml@refs/tags/v \ +--certificate-oidc-issuer https://token.actions.githubusercontent.com \ +quay.io/argoproj/argocd:v2.7.0 | jq +``` +The command should output the following if the container image was correctly verified: +```bash The following checks were performed on each of these signatures: - * The cosign claims were validated - * The signatures were verified against the specified public key -... + - The cosign claims were validated + - Existence of the claims in the transparency log was verified offline + - Any certificates were verified against the Fulcio roots. +[ + { + "critical": { + "identity": { + "docker-reference": "quay.io/argoproj/argo-cd" + }, + "image": { + "docker-manifest-digest": "sha256:63dc60481b1b2abf271e1f2b866be8a92962b0e53aaa728902caa8ac8d235277" + }, + "type": "cosign container image signature" + }, + "optional": { + "1.3.6.1.4.1.57264.1.1": "https://token.actions.githubusercontent.com", + "1.3.6.1.4.1.57264.1.2": "push", + "1.3.6.1.4.1.57264.1.3": "a6ec84da0eaa519cbd91a8f016cf4050c03323b2", + "1.3.6.1.4.1.57264.1.4": "Publish ArgoCD Release", + "1.3.6.1.4.1.57264.1.5": "argoproj/argo-cd", + "1.3.6.1.4.1.57264.1.6": "refs/tags/", + ... +``` + +*** +## Verification of container image with SLSA attestations + +A [SLSA](https://slsa.dev/) Level 3 provenance is generated using [slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator). + +The following command will verify the signature of an attestation and how it was issued. It will contain the payloadType, payload, and signature. + +Run the following command as per the [slsa-verifier documentation](https://github.com/slsa-framework/slsa-verifier/tree/main#containers): + +```bash +# Get the immutable container image to prevent TOCTOU attacks https://github.com/slsa-framework/slsa-verifier#toctou-attacks +IMAGE=quay.io/argoproj/argocd:v2.7.0 +IMAGE="${IMAGE}@"$(crane digest "${IMAGE}") +# Verify provenance, including the tag to prevent rollback attacks. +slsa-verifier verify-image "$IMAGE" \ + --source-uri github.com/argoproj/argo-cd \ + --source-tag v2.7.0 +``` + +If you only want to verify up to the major or minor verion of the source repository tag (instead of the full tag), use the `--source-versioned-tag` which performs semantic versioning verification: + +```shell +slsa-verifier verify-image "$IMAGE" \ + --source-uri github.com/argoproj/argo-cd \ + --source-versioned-tag v2 # Note: May use v2.7 for minor version verification. ``` -## Verification of signed assets + +The attestation payload contains a non-forgeable provenance which is base64 encoded and can be viewed by passing the `--print-provenance` option to the commands above: ```bash -cosign verify-blob --key cosign.pub --signature $(cat argocd--checksums.sig) argocd-$VERSION-checksums.txt -Verified OK +slsa-verifier verify-image "$IMAGE" \ + --source-uri github.com/argoproj/argo-cd \ + --source-tag v2.7.0 \ + --print-provenance | jq ``` -## Admission controllers -Cosign is compatible with several types of admission controllers. Please see the [Cosign documentation](https://docs.sigstore.dev/cosign/overview/#kubernetes-integrations) for supported controllers +If you prefer using cosign, follow these [instructions](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#cosign). + +!!! tip + `cosign` or `slsa-verifier` can both be used to verify image attestations. + Check the documentation of each binary for detailed instructions. + +*** + +## Verification of CLI artifacts with SLSA attestations + +A single attestation (`argocd-cli.intoto.jsonl`) from each release is provided. This can be used with [slsa-verifier](https://github.com/slsa-framework/slsa-verifier#verification-for-github-builders) to verify that a CLI binary was generated using Argo CD workflows on GitHub and ensures it was cryptographically signed. + +```bash +slsa-verifier verify-artifact argocd-linux-amd64 \ + --provenance-path argocd-cli.intoto.jsonl \ + --source-uri github.com/argoproj/argo-cd \ + --source-tag v2.7.0 +``` + +If you only want to verify up to the major or minor verion of the source repository tag (instead of the full tag), use the `--source-versioned-tag` which performs semantic versioning verification: + +```shell +slsa-verifier verify-artifact argocd-linux-amd64 \ + --provenance-path argocd-cli.intoto.jsonl \ + --source-uri github.com/argoproj/argo-cd \ + --source-versioned-tag v2 # Note: May use v2.7 for minor version verification. +``` + +The payload is a non-forgeable provenance which is base64 encoded and can be viewed by passing the `--print-provenance` option to the commands above: + +```bash +slsa-verifier verify-artifact argocd-linux-amd64 \ + --provenance-path argocd-cli.intoto.jsonl \ + --source-uri github.com/argoproj/argo-cd \ + --source-tag v2.7.0 \ + --print-provenance | jq +``` + +## Verification of Sbom + +A single attestation (`argocd-sbom.intoto.jsonl`) from each release is provided along with the sbom (`sbom.tar.gz`). This can be used with [slsa-verifier](https://github.com/slsa-framework/slsa-verifier#verification-for-github-builders) to verify that the SBOM was generated using Argo CD workflows on GitHub and ensures it was cryptographically signed. + +```bash +slsa-verifier verify-artifact sbom.tar.gz \ + --provenance-path argocd-sbom.intoto.jsonl \ + --source-uri github.com/argoproj/argo-cd \ + --source-tag v2.7.0 +``` + +*** +## Verification on Kubernetes + +### Policy controllers +!!! note + We encourage all users to verify signatures and provenances with your admission/policy controller of choice. Doing so will verify that an image was built by us before it's deployed on your Kubernetes cluster. + +Cosign signatures and SLSA provenances are compatible with several types of admission controllers. Please see the [cosign documentation](https://docs.sigstore.dev/cosign/overview/#kubernetes-integrations) and [slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#verification) for supported controllers. diff --git a/docs/operator-manual/tested-kubernetes-versions.md b/docs/operator-manual/tested-kubernetes-versions.md new file mode 100644 index 0000000000000..897620296a515 --- /dev/null +++ b/docs/operator-manual/tested-kubernetes-versions.md @@ -0,0 +1,6 @@ +| Argo CD version | Kubernetes versions | +|-----------------|---------------------| +| 2.7 | v1.26, v1.25, v1.24, v1.23 | +| 2.6 | v1.24, v1.23, v1.22 | +| 2.5 | v1.24, v1.23, v1.22 | + diff --git a/docs/operator-manual/tls.md b/docs/operator-manual/tls.md index 3b80e765f17dd..43409fc568f43 100644 --- a/docs/operator-manual/tls.md +++ b/docs/operator-manual/tls.md @@ -224,7 +224,10 @@ to not use TLS at all. In this case, you will need to: * Configure `argocd-repo-server` with TLS on the gRPC API disabled by specifying - the `--disable-tls` parameter to the pod container's startup arguments + the `--disable-tls` parameter to the pod container's startup arguments. + Also, consider restricting listening addresses to the loopback interface by specifying + `--listen 127.0.0.1` parameter, so that insecure endpoint is not exposed on + the pod's network interfaces, but still available to the side-car container. * Configure `argocd-server` and `argocd-application-controller` to not use TLS for connections to the `argocd-repo-server` by specifying the parameter `--repo-server-plaintext` to the pod container's startup arguments 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/ui-customization.md b/docs/operator-manual/ui-customization.md new file mode 100644 index 0000000000000..c6b463e577f50 --- /dev/null +++ b/docs/operator-manual/ui-customization.md @@ -0,0 +1,9 @@ +# UI Customization + +## Default Application Details View + +By default, the Application Details will show the `Tree` view. + +This can be configured on an Application basis, by setting the `pref.argocd.argoproj.io/default-view` annotation, accepting one of: `tree`, `pods`, `network`, `list` as values. + +For the Pods view, the default grouping mechanism can be configured using the `pref.argocd.argoproj.io/default-pod-sort` annotation, accepting one of: `node`, `parentResource`, `topLevelResource` as values. \ No newline at end of file diff --git a/docs/operator-manual/upgrading/1.8-2.0.md b/docs/operator-manual/upgrading/1.8-2.0.md index 8b623f70c73a6..fa74d15420d3e 100644 --- a/docs/operator-manual/upgrading/1.8-2.0.md +++ b/docs/operator-manual/upgrading/1.8-2.0.md @@ -1,4 +1,4 @@ -# v1.8 to v2.0 +# v1.8 to 2.0 ## Redis Upgraded to v6.2.1 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.3-2.4.md b/docs/operator-manual/upgrading/2.3-2.4.md index f877063226419..6e8c70ff8d9ab 100644 --- a/docs/operator-manual/upgrading/2.3-2.4.md +++ b/docs/operator-manual/upgrading/2.3-2.4.md @@ -1,5 +1,26 @@ # v2.3 to 2.4 +## Known Issues + +### Broken `project` filter before 2.4.27 + +Argo CD 2.4.0 introduced a breaking API change, renaming the `project` filter to `projects`. + +#### Impact to API clients + +A similar issue applies to other API clients which communicate with the Argo CD API server via its REST API. If the +client uses the `project` field to filter projects, the filter will not be applied. **The failing project filter could +have detrimental consequences if, for example, you rely on it to list Applications to be deleted.** + +#### Impact to CLI clients + +CLI clients older that v2.4.0 rely on client-side filtering and are not impacted by this bug. + +#### How to fix the problem + +Upgrade to Argo CD >=2.4.27, >=2.5.15, or >=2.6.6. This version of Argo CD will accept both `project` and `projects` as +valid filters. + ## KSonnet support is removed Ksonnet was deprecated in [2019](https://github.com/ksonnet/ksonnet/pull/914/files) and is no longer maintained. diff --git a/docs/operator-manual/upgrading/2.4-2.5.md b/docs/operator-manual/upgrading/2.4-2.5.md index f1e7d74dc7819..8971c7cd8e3a4 100644 --- a/docs/operator-manual/upgrading/2.4-2.5.md +++ b/docs/operator-manual/upgrading/2.4-2.5.md @@ -1,5 +1,57 @@ # v2.4 to 2.5 +## Known Issues + +### Broken `project` filter before 2.5.15 + +Argo CD 2.4.0 introduced a breaking API change, renaming the `project` filter to `projects`. + +#### Impact to API clients + +A similar issue applies to other API clients which communicate with the Argo CD API server via its REST API. If the +client uses the `project` field to filter projects, the filter will not be applied. **The failing project filter could +have detrimental consequences if, for example, you rely on it to list Applications to be deleted.** + +#### Impact to CLI clients + +CLI clients older that v2.4.0 rely on client-side filtering and are not impacted by this bug. + +#### How to fix the problem + +Upgrade to Argo CD >=2.4.27, >=2.5.15, or >=2.6.6. This version of Argo CD will accept both `project` and `projects` as +valid filters. + +### Broken matrix-nested git files generator in 2.5.14 + +Argo CD 2.5.14 introduced a bug in the matrix-nested git files generator. The bug only applies when the git files +generator is the second generator nested under a matrix. For example: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: guestbook +spec: + generators: + - matrix: + generators: + - clusters: {} + - git: + repoURL: https://git.example.com/org/repo.git + revision: HEAD + files: + - path: "defaults/*.yaml" + template: + # ... +``` + +The nested git files generator will produce no parameters, causing the matrix generator to also produce no parameters. +This will cause the ApplicationSet to produce no Applications. If the ApplicationSet controller is +[configured with the ability to delete applications](https://argo-cd.readthedocs.io/en/latest/operator-manual/applicationset/Controlling-Resource-Modification/), +it will delete all Applications which were previously created by the ApplicationSet. + +To avoid this issue, upgrade directly to >=2.5.15 or >= 2.6.6. + ## Configure RBAC to account for new `applicationsets` resource 2.5 introduces a new `applicationsets` [RBAC resource](https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/#rbac-resources-and-actions). @@ -34,7 +86,7 @@ p, role:org-admin, exec, create, *, allow ## argocd-cm plugins (CMPs) are deprecated Starting with Argo CD v2.5, installing config management plugins (CMPs) via the `argocd-cm` ConfigMap is deprecated. -Support will be removed in v2.6. +~~Support will be removed in v2.6.~~ Support will be removed in v2.7. You can continue to use the plugins by [installing them as sidecars](https://argo-cd.readthedocs.io/en/stable/user-guide/config-management-plugins/) on the repo-server Deployment. @@ -47,6 +99,8 @@ following message: > argocd-cm plugins are deprecated, and support will be removed in v2.6. Upgrade your plugin to be installed via sidecar. https://argo-cd.readthedocs.io/en/stable/user-guide/config-management-plugins/ +**NOTE:** removal of argocd-cm plugin support was delayed to v2.7. Update your logs scan to use `v2.7` instead of `v2.6`. + If you run `argocd app list` as admin, the list of Applications using deprecated plugins will be logged as a warning. ## Dex server TLS configuration @@ -97,14 +151,14 @@ When using `argocd app diff --local`, code from the repo server is run on the us In order to support CMPs and reduce local requirements, we have implemented *server-side generation* of local manifests via the `--server-side-generate` argument. For example, `argocd app diff --local repoDir --server-side-generate` will upload the contents of `repoDir` to the repo server and run your manifest generation pipeline against it, the same as it would for a Git repo. -In v2.6, the `--server-side-generate` argument will become the default and client-side generation will be removed. +In ~~v2.6~~ v2.7, the `--server-side-generate` argument will become the default, ~~and client-side generation will be removed~~ and client-side generation will be supported as an alternative. !!! warning The semantics of *where* Argo will start generating manifests within a repo has changed between client-side and server-side generation. With client-side generation, the application's path (`spec.source.path`) was ignored and the value of `--local-repo-root` was effectively used (by default `/` relative to `--local`). For example, given an application that has an application path of `/manifests`, you would have had to run `argocd app diff --local yourRepo/manifests`. This behavior did not match the repo server's process of downloading the full repo/chart and then beginning generation in the path specified in the application manifest. - When switching to server-side generation, `--local` should point to the root of your repo *without* including your `spec.source.path`. This is especially important to keep in mind when `--server-side-generate` becomes the default in v2.6. Existing scripts utilizing `diff --local` may break in v2.6 if `spec.source.path` was not `/`. + When switching to server-side generation, `--local` should point to the root of your repo *without* including your `spec.source.path`. This is especially important to keep in mind when `--server-side-generate` becomes the default in v2.7. Existing scripts utilizing `diff --local` may break in v2.7 if `spec.source.path` was not `/`. ## Upgraded Kustomize Version @@ -130,3 +184,21 @@ This note is just for clarity. No action is required. We [expected](../upgrading/2.3-2.4.md#enable-logs-rbac-enforcement) to enable logs RBAC enforcement by default in 2.5. We have decided not to do that in the 2.x series due to disruption for users of [Project Roles](../../user-guide/projects.md#project-roles). + +## `argocd app create` for old CLI versions fails with API version >=2.5.16 + +Starting with Argo CD 2.5.16, the API returns `PermissionDenied` instead of `NotFound` for Application `GET` requests if +the Application does not exist. + +The Argo CD CLI before versions starting with version 2.5.0-rc1 and before versions 2.5.16 and 2.6.7 does a `GET` +request before the `POST` request in `argocd app create`. The command does not gracefully handle the `PermissionDenied` +response and will therefore fail to create/update the Application. + +To solve the issue, upgrade the CLI to at least 2.5.16, or 2.6.7. + +CLIs older than 2.5.0-rc1 are unaffected. + +## Golang upgrade in 2.5.20 + +In 2.5.20, we upgrade the Golang version used to build Argo CD from 1.18 to 1.19. If you use Argo CD as a library, you +may need to upgrade your Go version. diff --git a/docs/operator-manual/upgrading/2.5-2.6.md b/docs/operator-manual/upgrading/2.5-2.6.md index 65864c88896ab..57f1373721445 100644 --- a/docs/operator-manual/upgrading/2.5-2.6.md +++ b/docs/operator-manual/upgrading/2.5-2.6.md @@ -1,5 +1,57 @@ # v2.5 to 2.6 +## Known Issues + +### Broken `project` filter before 2.6.6 + +Argo CD 2.4.0 introduced a breaking API change, renaming the `project` filter to `projects`. + +#### Impact to API clients + +A similar issue applies to other API clients which communicate with the Argo CD API server via its REST API. If the +client uses the `project` field to filter projects, the filter will not be applied. **The failing project filter could +have detrimental consequences if, for example, you rely on it to list Applications to be deleted.** + +#### Impact to CLI clients + +CLI clients older that v2.4.0 rely on client-side filtering and are not impacted by this bug. + +#### How to fix the problem + +Upgrade to Argo CD >=2.4.27, >=2.5.15, or >=2.6.6. This version of Argo CD will accept both `project` and `projects` as +valid filters. + +### Broken matrix-nested git files generator in 2.6.5 + +Argo CD 2.6.5 introduced a bug in the matrix-nested git files generator. The bug only applies when the git files +generator is the second generator nested under a matrix. For example: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: guestbook +spec: + generators: + - matrix: + generators: + - clusters: {} + - git: + repoURL: https://git.example.com/org/repo.git + revision: HEAD + files: + - path: "defaults/*.yaml" + template: + # ... +``` + +The nested git files generator will produce no parameters, causing the matrix generator to also produce no parameters. +This will cause the ApplicationSet to produce no Applications. If the ApplicationSet controller is +[configured with the ability to delete applications](https://argo-cd.readthedocs.io/en/latest/operator-manual/applicationset/Controlling-Resource-Modification/), +it will delete all Applications which were previously created by the ApplicationSet. + +To avoid this issue, upgrade directly to >=2.5.15 or >= 2.6.6. + ## ApplicationSets: `^` behavior change in Sprig's semver functions Argo CD 2.5 introduced [Go templating in ApplicationSets](https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/GoTemplate/). Go templates have access to the Sprig function library. @@ -10,4 +62,36 @@ Masterminds/semver v3 changed the behavior of the `^` prefix in semantic version ## Applications with suspended jobs now marked "Suspended" instead of "Progressing" Prior to Argo CD v2.6, an Application managing a suspended Job would be marked as "Progressing". This was confusing/unexpected behavior for many. Starting with v2.6, Argo CD will mark such Applications as "Suspended". -If you have processes which rely on the previous behavior (for example, a CI job with an argocd app wait call), update those before upgrading to v2.6. \ No newline at end of file +If you have processes which rely on the previous behavior (for example, a CI job with an argocd app wait call), update those before upgrading to v2.6. + +## The API Server now requires tokens to include the `aud` claim by default + +Argo CD v2.6 now requires that the `aud` claim be present in the token used to authenticate to the API Server. This is a +security improvement, as it prevents tokens from being used against the API Server which were not intended for it. + +If you rely on an OIDC provider which does not provide a `aud` claim, you can disable this requirement by setting the +`skipAudienceCheckWhenTokenHasNoAudience` flag to `true` in your Argo CD OIDC configuration. (See the +[OIDC configuration documentation](https://argo-cd.readthedocs.io/en/stable/operator-manual/user-management/#existing-oidc-provider) +for an example.) + +## Removal of argocd-cm plugin support delayed until 2.7 + +Support for argocd-cm plugins was previously scheduled for 2.6. At the time, sidecar plugins could not be specified by +name. Argo CD v2.6 introduces support for specifying sidecar plugins by name. + +Removal of argocd-cm plugin support has been delayed until 2.7 to provide a transition time for users who need to +specify plugins by name. + +## `argocd app create` for old CLI versions fails with API version >=2.6.7 + +Starting with Argo CD 2.6.7, the API returns `PermissionDenied` instead of `NotFound` for Application `GET` requests if +the Application does not exist. + +The Argo CD CLI before versions starting with version 2.5.0-rc1 and before versions 2.5.16 and 2.6.7 does a `GET` +request before the `POST` request in `argocd app create`. The command does not gracefully handle the `PermissionDenied` +response and will therefore fail to create/update the Application. + +To solve the issue, upgrade the CLI to at least 2.5.16, or 2.6.7. + +CLIs older than 2.5.0-rc1 are unaffected. + diff --git a/docs/operator-manual/upgrading/2.6-2.7.md b/docs/operator-manual/upgrading/2.6-2.7.md new file mode 100644 index 0000000000000..fa7fba02bf1b7 --- /dev/null +++ b/docs/operator-manual/upgrading/2.6-2.7.md @@ -0,0 +1,108 @@ +# v2.6 to 2.7 + +## Configure RBAC to account for new `extensions` resource + +2.7 introduces the new [Proxy Extensions][1] feature with a new `extensions` +[RBAC resource][2]. + +When you upgrade to 2.7, RBAC policies with `*` in the *resource* +field and `*` in the action field, it will automatically grant the +`extensions` privilege. + +The Proxy Extension feature is disabled by default, however it is +recommended to check your RBAC configurations to enforce the least +necessary privileges. + +Example +Old: + +```csv +p, role:org-admin, *, *, *, allow +``` + +New: + +```csv +p, role:org-admin, clusters, create, my-proj/*, allow +p, role:org-admin, projects, create, my-proj/*, allow +p, role:org-admin, applications, create, my-proj/*, allow +p, role:org-admin, repositories, create, my-proj/*, allow +p, role:org-admin, certificates, create, my-proj/*, allow +p, role:org-admin, accounts, create, my-proj/*, allow +p, role:org-admin, gpgkeys, create, my-proj/*, allow +# If you don't want to grant the new permission, don't include the following line +p, role:org-admin, extensions, invoke, my-proj/*, allow +``` + +## Upgraded Helm Version + +Note that bundled Helm version has been upgraded from 3.10.3 to 3.11.2. + +## Upgraded Kustomize Version + +Note that bundled Kustomize version has been upgraded from 4.5.7 to 5.0.1. + +## Notifications: `^` behavior change in Sprig's semver functions +Argo CD 2.7 upgrades Sprig templating specifically within Argo CD notifications to v3. That upgrade includes an upgrade of [Masterminds/semver](https://github.com/Masterminds/semver/releases) to v3. + +Masterminds/semver v3 changed the behavior of the `^` prefix in semantic version constraints. If you are using sprig template functions in your notifications templates which include references to [Sprig's semver functions](https://masterminds.github.io/sprig/semver.html) and use the `^` prefix, read the [Masterminds/semver changelog](https://github.com/Masterminds/semver/releases/tag/v3.0.0) to understand how your notifications' behavior may change. + +## Tini as entrypoint + +The manifests are now using [`tini` as entrypoint][3], instead of `entrypoint.sh`. Until 2.8, `entrypoint.sh` is retained for upgrade compatibility. This means that the deployment manifests have to be updated after upgrading to 2.7, and before upgrading to 2.8 later. In case the manifests are updated before moving to 2.8, the containers will not be able to start. + +[1]: ../../developer-guide/extensions/proxy-extensions.md +[2]: https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/#the-extensions-resource +[3]: https://github.com/argoproj/argo-cd/pull/12707 + + +## Deep Links template updates + +Deep Links now allow you to access other values like `cluster`, `project`, `application` and `resource` in the url and condition templates for specific categories of links. +The templating syntax has also been updated to be prefixed with the type of resource you want to access for example previously if you had a `resource.links` config like : +```yaml + resource.links: | + - url: https://mycompany.splunk.com?search={{.metadata.name}} + title: Splunk + if: kind == "Pod" || kind == "Deployment" +``` +This would become : +```yaml + resource.links: | + - url: https://mycompany.splunk.com?search={{.resource.metadata.name}}&env={{.project.metadata.label.env}} + title: Splunk + if: resource.kind == "Pod" || resource.kind == "Deployment" +``` + +Read the full [documentation](../deep_links.md) to see all possible combinations of values accessible fo each category of links. + +## Support of `helm.sh/resource-policy` annotation + +Argo CD now supports the `helm.sh/resource-policy` annotation to control the deletion of resources. The behavior is the same as the behavior of +`argocd.argoproj.io/sync-options: Delete=false` annotation: if the annotation is present and set to `keep`, the resource will not be deleted +when the application is deleted. + +## Check your Kustomize patches for `--redis` changes + +Starting in Argo CD 2.7, the install manifests no longer pass the Redis server name via `--redis`. + +If your environment uses Kustomize JSON patches to modify the Redis server name, the patch might break when you upgrade +to the 2.7 manifests. If it does, you can remove the patch and instead set the Redis server name via the `redis.server` +field in the argocd-cmd-params-cm ConfigMap. That value will be passed to the necessary components via `valueFrom` +environment variables. + +## `argocd applicationset` CLI incompatibilities for ApplicationSets with list generators + +If you are running Argo CD v2.7.0-2.7.2 server-side, then CLI versions outside that range will incorrectly handle list +generators. That is because the gRPC interface for those versions used the `elements` field number for the new +`elementsYaml` field. + +If you are running the Argo CD CLI versions v2.7.0-2.7.2 with a server-side version of v2.7.3 or later, then the CLI +will send the contents of the `elements` field to the server, which will interpret it as the `elementsYaml` field. This +will cause the ApplicationSet to fail at runtime with an error similar to this: + +``` +error unmarshling decoded ElementsYaml error converting YAML to JSON: yaml: control characters are not allowed +``` + +Be sure to use CLI version v2.7.3 or later with server-side version v2.7.3 or later. diff --git a/docs/operator-manual/upgrading/2.7-2.8.md b/docs/operator-manual/upgrading/2.7-2.8.md new file mode 100644 index 0000000000000..c42a97a1f429c --- /dev/null +++ b/docs/operator-manual/upgrading/2.7-2.8.md @@ -0,0 +1,73 @@ +# v2.7 to 2.8 + +## Support dropped for argocd-cm plugins + +Config Management Plugins installed via the argocd-cm ConfigMap will not work starting with v2.8. + +See the [migration guide](https://argo-cd.readthedocs.io/en/stable/operator-manual/config-management-plugins/#migrating-from-argocd-cm-plugins) +to upgrade your plugin. + +## Tini as entrypoint + +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 +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 +properly before moving to 2.8. + +## Filtering applied to cluster `List` API endpoint + +Prior to `v2.8`, the `List` endpoint on the `ClusterService` did **not** filter +clusters when responding, despite accepting query parameters. This bug has +been addressed, and query parameters are now taken into account to filter the +resulting list of clusters. + +## Configure RBAC to account for new actions + +2.8 introduces three new actions: + +* Create a Job from a CronJob +* Create a Workflow from a CronWorkflow +* Create a Workflow from a WorkflowTemplate + +When you upgrade to 2.8, RBAC policies with `applications` in the *resource* +field and `*` or `action/*` in the action field, it will automatically grant the +ability to use these new actions. + +If you would like to avoid granting these new permissions, you can update your RBAC policies to be more specific. + +### Example + +Old: + +```csv +p, role:action-runner, applications, actions/, *, allow +``` + +New: + +```csv +p, role:action-runner, applications, action/argoproj.io/Rollout/abort, *, allow +p, role:action-runner, applications, action/argoproj.io/Rollout/promote-full, *, allow +p, role:action-runner, applications, action/argoproj.io/Rollout/retry, *, allow +p, role:action-runner, applications, action/argoproj.io/Rollout/resume, *, allow +p, role:action-runner, applications, action/argoproj.io/Rollout/restart, *, allow +p, role:action-runner, applications, action/argoproj.io/AnalysisRun/terminate, *, allow +p, role:action-runner, applications, action/apps/DaemonSet/restart, *, allow +p, role:action-runner, applications, action/apps/StatefulSet/restart, *, allow +p, role:action-runner, applications, action/apps/Deployment/pause, *, allow +p, role:action-runner, applications, action/apps/Deployment/resume, *, allow +p, role:action-runner, applications, action/apps/Deployment/restart, *, allow + +# If you don't want to grant the new permissions, don't include the following lines +p, role:action-runner, applications, action/argoproj.io/WorkflowTemplate/create-workflow, *, allow +p, role:action-runner, applications, action/argoproj.io/CronWorkflow/create-workflow, *, allow +p, role:action-runner, applications, action/batch/CronJob/create-job, *, allow +``` + +## Change default file open mode + +In version 2.7, the CMP plugin was changed to open Git/Helm files with all executable bits set (unless `preserveFileMode` was specified). +Version 2.8 removes the executable bits in cases where they are not necessary. 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..7fddc75ab7e86 --- /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.3. diff --git a/docs/operator-manual/upgrading/overview.md b/docs/operator-manual/upgrading/overview.md index 0f95b89066c86..742c7b191b57a 100644 --- a/docs/operator-manual/upgrading/overview.md +++ b/docs/operator-manual/upgrading/overview.md @@ -37,6 +37,11 @@ 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) * [v2.4 to v2.5](./2.4-2.5.md) * [v2.3 to v2.4](./2.3-2.4.md) * [v2.2 to v2.3](./2.2-2.3.md) diff --git a/docs/operator-manual/user-management/google.md b/docs/operator-manual/user-management/google.md index 7113e51018ca2..366a1e9863d76 100644 --- a/docs/operator-manual/user-management/google.md +++ b/docs/operator-manual/user-management/google.md @@ -142,17 +142,6 @@ data: ## OpenID Connect plus Google Groups using Dex ---- -!!! warning "Limited group information" - - When using this feature you'll only receive the list of groups the user is a direct member. - - So, lets say you have this hierarchy of groups and subgroups: - `all@example.com --> tech@example.com --> devs@example.com --> you@example.com` - The only group you would receive through Dex would be `devs@example.com` - ---- - We're going to use Dex's `google` connector to get additional Google Groups information from your users, allowing you to use group membership on your RBAC, i.e., giving `admin` role to the whole `sysadmins@yourcompany.com` group. This connector uses two different credentials: @@ -211,7 +200,7 @@ Go through the same steps as in [OpenID Connect using Dex](#openid-connect-using defaultMode: 420 secretName: argocd-google-groups-json -3. Edit `argocd-cm` and add the following `dex.config` to the data section, replacing `clientID` and `clientSecret` with the values you saved before, `adminEmail` with the address for the admin user you're going to impersonate, and editing `redirectURI` with your Argo CD domain: +3. Edit `argocd-cm` and add the following `dex.config` to the data section, replacing `clientID` and `clientSecret` with the values you saved before, `adminEmail` with the address for the admin user you're going to impersonate, and editing `redirectURI` with your Argo CD domain (note that the `type` is now `google` instead of `oidc`): dex.config: | connectors: @@ -229,6 +218,20 @@ Go through the same steps as in [OpenID Connect using Dex](#openid-connect-using 5. Login to Argo CD and go to the "User info" section, were you should see the groups you're member ![User info](../../assets/google-groups-membership.png) 6. Now you can use groups email addresses to give RBAC permissions +7. Dex (> v2.31.0) can also be configure to fetch transitive group membership as follows: + + dex.config: | + connectors: + - config: + redirectURI: https://argocd.example.com/api/dex/callback + clientID: XXXXXXXXXXXXX.apps.googleusercontent.com + clientSecret: XXXXXXXXXXXXX + serviceAccountFilePath: /tmp/oidc/googleAuth.json + adminEmail: admin-email@example.com + fetchTransitiveGroupMembership: True + type: google + id: google + name: Google ### References 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 c0a70eae47429..c002b77ada5ed 100644 --- a/docs/operator-manual/user-management/index.md +++ b/docs/operator-manual/user-management/index.md @@ -3,7 +3,7 @@ Once installed Argo CD has one built-in `admin` user that has full access to the system. It is recommended to use `admin` user only for initial configuration and then switch to local users or configure SSO integration. -## Local users/accounts (v1.5) +## Local users/accounts The local users/accounts feature serves two main use-cases: @@ -44,6 +44,24 @@ Each user might have two capabilities: * apiKey - allows generating authentication tokens for API access * login - allows to login using UI +### Delete user + +In order to delete a user, you must remove the corresponding entry defined in the `argocd-cm` ConfigMap: + +Example: + +```bash +kubectl patch -n argocd cm argocd-cm --type='json' -p='[{"op": "remove", "path": "/data/accounts.alice"}]' +``` + +It is recommended to also remove the password entry in the `argocd-secret` Secret: + +Example: + +```bash +kubectl patch -n argocd secrets argocd-secret --type='json' -p='[{"op": "remove", "path": "/data/accounts.alice.password"}]' +``` + ### Disable admin user As soon as additional users are created it is recommended to disable `admin` user: @@ -183,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: @@ -224,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 ``` @@ -246,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 @@ -276,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 @@ -301,6 +319,19 @@ data: issuer: https://dev-123456.oktapreview.com clientID: aaaabbbbccccddddeee clientSecret: $oidc.okta.clientSecret + + # Optional list of allowed aud claims. If omitted or empty, defaults to the clientID value above (and the + # cliClientID, if that is also specified). If you specify a list and want the clientID to be allowed, you must + # explicitly include it in the list. + # Token verification will pass if any of the token's audiences matches any of the audiences in this list. + allowedAudiences: + - aaaabbbbccccddddeee + - qqqqwwwweeeerrrrttt + + # Optional. If false, tokens without an audience will always fail validation. If true, tokens without an audience + # will always pass validation. + # Defaults to true for Argo CD < 2.6.0. Defaults to false for Argo CD >= 2.6.0. + skipAudienceCheckWhenTokenHasNoAudience: true # Optional set of OIDC scopes to request. If omitted, defaults to: ["openid", "profile", "email", "groups"] requestedScopes: ["openid", "profile", "email", "groups"] @@ -313,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 @@ -350,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 @@ -358,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 @@ -405,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 @@ -449,7 +500,7 @@ data: #### Alternative -If you want to store sensitive data in **another** Kubernetes `Secret`, instead of `argocd-secret`. ArgoCD knows to check the keys under `data` in your Kubernetes `Secret` for a corresponding key whenever a value in a configmap starts with `$`, then your Kubernetes `Secret` name and `:` (colon). +If you want to store sensitive data in **another** Kubernetes `Secret`, instead of `argocd-secret`. ArgoCD knows to check the keys under `data` in your Kubernetes `Secret` for a corresponding key whenever a value in a configmap or secret starts with `$`, then your Kubernetes `Secret` name and `:` (colon). Syntax: `$:` diff --git a/docs/operator-manual/user-management/keycloak.md b/docs/operator-manual/user-management/keycloak.md index bc88c436e8ef0..6f0c99de0dec2 100644 --- a/docs/operator-manual/user-management/keycloak.md +++ b/docs/operator-manual/user-management/keycloak.md @@ -9,19 +9,24 @@ to determine privileges in Argo. ## Creating a new client in Keycloak First we need to setup a new client. Start by logging into your keycloak server, select the realm you want to use (`master` by default) -and then go to __Clients__ and click the __create__ button top right. +and then go to __Clients__ and click the __Create client__ button at the top. ![Keycloak add client](../../assets/keycloak-add-client.png "Keycloak add client") -Configure the client by setting the __Access Type__ to _confidential_ and set the Valid Redirect URIs to the callback url for your ArgoCD -hostname. It should be https://{hostname}/auth/callback (you can also leave the default less secure https://{hostname}/* ). You can also set the -__Base URL__ to _/applications_. +Enable the __Client authentication__. -If you want to allow command line access, __Access Type__ must be set to _public_ and you also need to add http://localhost:8085/auth/callback in the list of Valid Redirect URIs. Then users can login using `argocd login {hostname} --sso`. +![Keycloak add client Step 2](../../assets/keycloak-add-client_2.png "Keycloak add client Step 2") + +Configure the client by setting the __Root URL__, __Web origins__, __Admin URL__ to the hostname (https://{hostname}). + +Also you can set __Home URL__ to your _/applications_ path and __Valid Post logout redirect URIs__ to "+". + +The Valid Redirect URIs should be set to https://{hostname}/auth/callback (you can also set the less secure https://{hostname}/* for testing/development purposes, +but it's not recommended in production). ![Keycloak configure client](../../assets/keycloak-configure-client.png "Keycloak configure client") -Make sure to click __Save__. You should now have a new tab called __Credentials__. You can copy the Secret that we'll use in our ArgoCD +Make sure to click __Save__. There should be a tab called __Credentials__. You can copy the Secret that we'll use in our ArgoCD configuration. ![Keycloak client secret](../../assets/keycloak-client-secret.png "Keycloak client secret") @@ -34,21 +39,18 @@ To do this we'll start by creating a new __Client Scope__ called _groups_. ![Keycloak add scope](../../assets/keycloak-add-scope.png "Keycloak add scope") Once you've created the client scope you can now add a Token Mapper which will add the groups claim to the token when the client requests -the groups scope. Make sure to set the __Name__ as well as the __Token Claim Name__ to _groups_. +the groups scope. In the Tab "Mappers", click on "Configure a new mapper" and choose __Group Membership__. +Make sure to set the __Name__ as well as the __Token Claim Name__ to _groups_. Also disable the "Full group path". ![Keycloak groups mapper](../../assets/keycloak-groups-mapper.png "Keycloak groups mapper") -We can now configure the client to provide the _groups_ scope. You can now assign the _groups_ scope either to the __Assigned Default Client Scopes__ -or to the __Assigned Optional Client Scopes__. If you put it in the Optional category you will need to make sure that ArgoCD requests the scope in -it's OIDC configuration. +We can now configure the client to provide the _groups_ scope. Go back to the client we've created earlier and go to the Tab "Client Scopes". +Click on "Add client scope", choose the _groups_ scope and add it either to the __Default__ or to the __Optional__ Client Scope. If you put it in the Optional +category you will need to make sure that ArgoCD requests the scope in its OIDC configuration. Since we will always want group information, I recommend +using the Default category. ![Keycloak client scope](../../assets/keycloak-client-scope.png "Keycloak client scope") -Since we will always want group information, I recommend using the Default category. Make sure you click __Add selected__ -and that the _groups_ claim is in the correct list on the __right__. - -![Keycloak client scope selected](../../assets/keycloak-client-scope-selected.png "Keycloak client scope selected") - Create a group called _ArgoCDAdmins_ and have your current user join the group. ![Keycloak user group](../../assets/keycloak-user-group.png "Keycloak user group") @@ -94,8 +96,9 @@ data: ``` Make sure that: + - __issuer__ ends with the correct realm (in this example _master_) -- __issuer__ on Keycloak releases older than version 17 the URL must include /auth (in this expample /auth/realms/master) +- __issuer__ on Keycloak releases older than version 17 the URL must include /auth (in this example /auth/realms/master) - __clientID__ is set to the Client ID you configured in Keycloak - __clientSecret__ points to the right key you created in the _argocd-secret_ Secret - __requestedScopes__ contains the _groups_ claim if you didn't add it to the Default scopes 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/user-management/openunison.md b/docs/operator-manual/user-management/openunison.md index 469d85f14935b..fecaafd074aa1 100644 --- a/docs/operator-manual/user-management/openunison.md +++ b/docs/operator-manual/user-management/openunison.md @@ -19,7 +19,7 @@ metadata: spec: accessTokenSkewMillis: 120000 accessTokenTimeToLive: 1200000 - authChainName: LoginService + authChainName: login-service clientId: argocd codeLastMileKeyName: lastmile-oidc codeTokenSkewMilis: 60000 diff --git a/docs/operator-manual/user-management/zitadel.md b/docs/operator-manual/user-management/zitadel.md new file mode 100644 index 0000000000000..08841983bc95f --- /dev/null +++ b/docs/operator-manual/user-management/zitadel.md @@ -0,0 +1,210 @@ +# Zitadel +Please also consult the [Zitadel Documentation](https://zitadel.com/docs). +## Integrating Zitadel and ArgoCD +These instructions will take you through the entire process of getting your ArgoCD application authenticating and authorizing with Zitadel. You will create an application within Zitadel and configure ArgoCD to use Zitadel for authentication using roles set in Zitadel to determine privileges in ArgoCD. + +The following steps are required to integrate ArgoCD with Zitadel: +1. Create a new project and a new application in Zitadel +2. Configure the application in Zitadel +3. Set up roles in Zitadel +4. Set up an action in Zitadel +5. Configure ArgoCD configmaps +6. Test the setup + +The following values will be used in this example: +- Zitadel FQDN: `auth.example.com` +- Zitadel Project: `argocd-project` +- Zitadel Application: `argocd-application` +- Zitadel Action: `groupsClaim` +- ArgoCD FQDN: `argocd.example.com` +- ArgoCD Administrator Role: `argocd_administrators` +- ArgoCD User Role: `argocd_users` + +You may choose different values in your setup; these are used to keep the guide consistent. + +## Setting up your project and application in Zitadel +First, we will create a new project within Zitadel. Go to **Projects** and select **Create New Project**. +You should now see the following screen. + +![Zitadel Project](../../assets/zitadel-project.png "Zitadel Project") + +Check the following options: +- Assert Roles on Authentication +- Check authorization on Authentication + +![Zitadel Project Settings](../../assets/zitadel-project-settings.png "Zitadel Project Settings") + +### Roles + +Go to **Roles** and click **New**. Create the following two roles. Use the specified values below for both fields **Key** and **Group**. +- `argocd_administrators` +- `argocd_users` + +Your roles should now look like this: + +![Zitadel Project Roles](../../assets/zitadel-project-roles.png "Zitadel Project Roles") + +### Authorizations + +Next, go to **Authorizations** and assign your user the role `argocd_administrators`. +Click **New**, enter the name of your user and click **Continue**. Select the role `argocd_administrators` and click **Save**. + +Your authorizations should now look like this: + +![Zitadel Project Authorizations](../../assets/zitadel-project-authorizations.png "Zitadel Project Authorizations") + +### Creating an application + +Go to **General** and create a new application. Name the application `argocd-application`. + +For type of the application, select **WEB** and click continue. + +![Zitadel Application Setup Step 1](../../assets/zitadel-application-1.png "Zitadel Application Setup Step 1") + +Select **CODE** and continue. + +![Zitadel Application Setup Step 2](../../assets/zitadel-application-2.png "Zitadel Application Setup Step 2") + +Next, we will set up the redirect and post-logout URIs. Set the following values: +- Redirect URI: `https://argocd.example.com/auth/callback` +- Post Logout URI: `https://argocd.example.com` + +The post logout URI is optional. In the example setup users will be taken back to the ArgoCD login page after logging out. + +![Zitadel Application Setup Step 3](../../assets/zitadel-application-3.png "Zitadel Application Setup Step 3") + +Verify your configuration on the next screen and click **Create** to create the application. + +![Zitadel Application Setup Step 4](../../assets/zitadel-application-4.png "Zitadel Application Setup Step 4") + +After clicking **Create** you will be shown the `ClientId` and the `ClientSecret` for your application. Make sure to copy the ClientSecret as you will not be able to retrieve it after closing this window. +For our example, the following values are used: +- ClientId: `227060711795262483@argocd-project` +- ClientSecret: `UGvTjXVFAQ8EkMv2x4GbPcrEwrJGWZ0sR2KbwHRNfYxeLsDurCiVEpa5bkgW0pl0` + +![Zitadel Application Secrets](../../assets/zitadel-application-secrets.png "Zitadel Application Secrets") + +Once you have saved the ClientSecret in a safe place, click **Close** to complete creating the application. + +Go to **Token Settings** and enable the following options: +- User roles inside ID Token +- User Info inside ID Token + +![Zitadel Application Settings](../../assets/zitadel-application-settings.png "Zitadel Application Settings") + +## Setting up an action in Zitadel + +To include the role of the user in the token issued by Zitadel, we will need to set up a Zitadel Action. The authorization in ArgoCD will be determined by the role contained within the auth token. +Go to **Actions**, click **New** and choose `groupsClaim` as the name of your action. + +Paste the following code into the action: + +```javascript +/** + * sets the roles an additional claim in the token with roles as value an project as key + * + * The role claims of the token look like the following: + * + * // added by the code below + * "groups": ["{roleName}", "{roleName}", ...], + * + * Flow: Complement token, Triggers: Pre Userinfo creation, Pre access token creation + * + * @param ctx + * @param api + */ +function groupsClaim(ctx, api) { + if (ctx.v1.user.grants === undefined || ctx.v1.user.grants.count == 0) { + return; + } + + let grants = []; + ctx.v1.user.grants.grants.forEach((claim) => { + claim.roles.forEach((role) => { + grants.push(role); + }); + }); + + api.v1.claims.setClaim("groups", grants); +} +``` + +Check **Allowed To Fail** and click **Add** to add your action. + +*Note: If **Allowed To Fail** is not checked and a user does not have a role assigned, it may be possible that the user is no longer able to log in to Zitadel as the login flow fails when the action fails.* + +Next, add your action to the **Complement Token** flow. Select the **Complement Token** flow from the dropdown and click **Add trigger**. +Add your action to both triggers **Pre Userinfo creation** and **Pre access token creation**. + +Your Actions page should now look like the following screenshot: + +![Zitadel Actions](../../assets/zitadel-actions.png "Zitadel Actions") + + +## Configuring the ArgoCD configmaps + +Next, we will configure two ArgoCD configmaps: +- [argocd-cm.yaml](https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/argocd-cm.yaml) +- [argocd-rbac-cm.yaml](https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/argocd-rbac-cm.yaml) + +Configure your configmaps as follows while making sure to replace the relevant values such as `url`, `issuer`, `clientID`, `clientSecret` and `logoutURL` with ones matching your setup. + +### argocd-cm.yaml +```yaml +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cm + namespace: argocd + labels: + app.kubernetes.io/part-of: argocd +data: + admin.enabled: "false" + url: https://argocd.example.com + oidc.config: | + name: Zitadel + issuer: https://auth.example.com + clientID: 227060711795262483@argocd-project + clientSecret: UGvTjXVFAQ8EkMv2x4GbPcrEwrJGWZ0sR2KbwHRNfYxeLsDurCiVEpa5bkgW0pl0 + requestedScopes: + - openid + - profile + - email + - groups + logoutURL: https://auth.example.com/oidc/v1/end_session +``` + +### argocd-rbac-cm.yaml +```yaml +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-rbac-cm + namespace: argocd + labels: + app.kubernetes.io/part-of: argocd +data: + scopes: '[groups]' + policy.csv: | + g, argocd_administrators, role:admin + g, argocd_users, role:readonly + policy.default: '' +``` + +The roles specified under `policy.csv` must match the roles configured in Zitadel. +The Zitadel role `argocd_administrators` will be assigned the ArgoCD role `admin` granting admin access to ArgoCD. +The Zitadel role `argocd_users` will be assigned the ArgoCD role `readonly` granting read-only access to ArgoCD. + +Deploy your ArgoCD configmaps. ArgoCD and Zitadel should now be set up correctly to allow users to log in to ArgoCD using Zitadel. + +## Testing the setup + +Go to your ArgoCD instance. You should now see the **LOG IN WITH ZITADEL** button above the usual username/password login. + +![Zitadel ArgoCD Login](../../assets/zitadel-argocd-login.png "Zitadel ArgoCD Login") + +After logging in with your Zitadel user go to **User Info**. If everything is set up correctly you should now see the group `argocd_administrators` as shown below. + +![Zitadel ArgoCD User Info](../../assets/zitadel-argocd-user-info.png "Zitadel ArgoCD User Info") diff --git a/docs/operator-manual/webhook.md b/docs/operator-manual/webhook.md index 9a93d6ff0208c..a0e6c8deba1b2 100644 --- a/docs/operator-manual/webhook.md +++ b/docs/operator-manual/webhook.md @@ -4,7 +4,7 @@ Argo CD polls Git repositories every three minutes to detect changes to the manifests. To eliminate this delay from polling, the API server can be configured to receive webhook events. Argo CD supports -Git webhook notifications from GitHub, GitLab, Bitbucket, Bitbucket Server and Gogs. The following explains how to configure +Git webhook notifications from GitHub, GitLab, Bitbucket, Bitbucket Server, Azure DevOps and Gogs. The following explains how to configure a Git webhook for GitHub, but the same process should be applicable to other providers. !!! note @@ -12,19 +12,28 @@ a Git webhook for GitHub, but the same process should be applicable to other pro the same. A hook event for a push to branch `x` will trigger a refresh for an app pointing at the same repo with `targetRevision: refs/tags/x`. -### 1. Create The WebHook In The Git Provider +## 1. Create The WebHook In The Git Provider In your Git provider, navigate to the settings page where webhooks can be configured. The payload URL configured in the Git provider should use the `/api/webhook` endpoint of your Argo CD instance (e.g. `https://argocd.example.com/api/webhook`). If you wish to use a shared secret, input an arbitrary value in the secret. This value will be used when configuring the webhook in the next step. +## Github + ![Add Webhook](../assets/webhook-config.png "Add Webhook") !!! note When creating the webhook in GitHub, the "Content type" needs to be set to "application/json". The default value "application/x-www-form-urlencoded" is not supported by the library used to handle the hooks -### 2. Configure Argo CD With The WebHook Secret (Optional) +## Azure DevOps + +![Add Webhook](../assets/azure-devops-webhook-config.png "Add Webhook") + +Azure DevOps optionally supports securing the webhook using basic authentication. To use it, specify the username and password in the webhook configuration and configure the same username/password in `argocd-secret` Kubernetes secret in +`webhook.azuredevops.username` and `webhook.azuredevops.password` keys. + +## 2. Configure Argo CD With The WebHook Secret (Optional) Configuring a webhook shared secret is optional, since Argo CD will still refresh applications related to the Git repository, even with unauthenticated webhook events. This is safe to do since @@ -32,24 +41,26 @@ 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 | -|-----------------| ---------------------------------| +|-----------------|----------------------------------| | GitHub | `webhook.github.secret` | | GitLab | `webhook.gitlab.secret` | | BitBucket | `webhook.bitbucket.uuid` | | BitBucketServer | `webhook.bitbucketserver.secret` | | Gogs | `webhook.gogs.secret` | +| 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: @@ -79,6 +90,20 @@ stringData: # gogs server webhook secret webhook.gogs.secret: shhhh! it's a gogs server secret + + # azuredevops username and password + webhook.azuredevops.username: admin + webhook.azuredevops.password: secret-password ``` After saving, the changes should take effect automatically. + +### Alternative + +If you want to store webhook data in **another** Kubernetes `Secret`, instead of `argocd-secret`. ArgoCD knows to check the keys under `data` in your Kubernetes `Secret` starts with `$`, then your Kubernetes `Secret` name and `:` (colon). + +Syntax: `$:` + +> NOTE: Secret must have label `app.kubernetes.io/part-of: argocd` + +For more information refer to the corresponding section in the [User Management Documentation](user-management/index.md#alternative). diff --git a/docs/proposals/002-ui-extensions.md b/docs/proposals/002-ui-extensions.md index 8fa02d25fd11c..583888da68c66 100644 --- a/docs/proposals/002-ui-extensions.md +++ b/docs/proposals/002-ui-extensions.md @@ -63,7 +63,7 @@ As an operator, I would like to configure Argo CD to perform pre-defined actions ## Proposal -A new `ArgoCDExtension` CRD would be introduced which will allow operators configure Argo CD to understand how to handle and visualize custom resources. Visualizing a object requires javascript to render the object, and health/actions require lua scripts. Aas such, the extension CR would need to point to some location where the javascript/lua code would be hosted. +A new `ArgoCDExtension` CRD would be introduced which will allow operators configure Argo CD to understand how to handle and visualize custom resources. Visualizing a object requires javascript to render the object, and health/actions require lua scripts. As such, the extension CR would need to point to some location where the javascript/lua code would be hosted. It is proposed that a git repository be used to contain the javascript code, as well as the lua scripts necessary to assess health or perform actions of a resource. diff --git a/docs/proposals/004-scalability-benchmarking.md b/docs/proposals/004-scalability-benchmarking.md new file mode 100644 index 0000000000000..43c44771850a7 --- /dev/null +++ b/docs/proposals/004-scalability-benchmarking.md @@ -0,0 +1,122 @@ +--- +title: Argo CD Scalability Benchmarking +authors: + - "@andklee" + - "@csantanapr" + - "@morey-tech" + - "@nimakaviani" +sponsors: + - +reviewers: + - + - +approvers: + - + - +creation-date: 2023-02-28 +last-updated: 2023-02-28 +--- + +# Argo CD Scalability Benchmarking + +## Open Questions [optional] +* What are the scalability factors to prioritize when benchmarking Argo CD? + * Reconciliation time for all, one, or several applications in the cluster. + +## Motivation +Users of Argo CD are interested to know how to scale Argo CD, what configuration tweaks and deployment options they have, and how far they can push resources (in terms of the number of supported applications, Git repositories, managing clusters, etc.). + +While the Argo CD documentation [discusses options](https://argo-cd.readthedocs.io/en/stable/operator-manual/high_availability/#scaling-up) to scale up, the actual process is not clear and, as articulated [in this thread](https://github.com/argoproj/argo-cd/issues/9633), oftentimes a point of confusion for users. + +By running large-scale benchmarking, we aim at helping the Argo CD community with the following: + +* Give confidence to organizations running at a significant scale (_needs to be quantified_) that Argo CD can support their use-case, with empirical evidence. +* Create clear guidelines for scaling Argo CD based on the key scalability factors. +* Provide recommendations for which topology is best suited for users based on their needs. +* Determine what work, if any, is needed to improve the scalability of Argo CD. + +### Goals +1. Create a standard set of repeatable benchmarking procedures to objectively measure the limitations of Argo CD. + 1. This may result in a new `argo-cd-benchmarking` repo under `argoproj-labs` so that anyone can easily replicate it and the development of the procedures can happen outside of the lifecycle for Argo CD (unlike [the current `gen-resources` hack](https://github.com/argoproj/argo-cd/tree/master/hack/gen-resources) in the main project). + 2. Include detailed test scenarios that account for key scalability factors that allow for easy tweaking of the parameters to simplify testing of alternative scenarios. +2. Determine the baseline for when tweaking is required on the default configuration (resource allocations and replicas). + 1. One cluster, Applications in In-cluster, default resource allocations. +3. Quantify how tweaking existing parameters (replicas, sharding, parallelism, etc) impacts the performance of Argo CD. +4. Provide a set of metrics and thresholds that will provide a basis for automatically scaling the Argo CD components and alerting for when performance is being impacted by limitations. +5. All tooling, recommendations, examples, and scenarios will be vendor-agnostic. +### Non-Goals +* This proposal does not intend to cover the implementation of any auto-scaling based on the metrics and thresholds determined by the scalability benchmarking. A separate proposal will be used for any auto-scaling enhancements. +* This proposal does not intend to add testing that determines how a change impacts the scalability of Argo CD based on the benchmarks. +* We do not intend to analyze the cost implications of running different topologies and purely focus on scalability requirements from a technology perspective. + +### Initial Members +The initial members for this proposal and their affiliations are: +| Name | Company | +|-----------------------------------------------------|-----------| +| [Andrew Lee](https://github.com/andklee) | AWS | +| [Carlos Santana](https://github.com/csantanapr) | AWS | +| [Nicholas Morey](https://github.com/morey-tech) | Akuity | +| [Nima Kaviani](https://github.com/nimakaviani) | AWS | + +With the introduction of [the proposed Scalability SIG](https://github.com/argoproj/argoproj/pull/192), the members participating in the proposal may change. + +Any community member is welcome to participate in the work for this proposal. Either by joining the Scalability SIG or through contributing to the proposed `argoproj-labs/argo-cd-benchmarking` repository containing the tooling. + +## Proposal +1. Create new `argo-cd-benchmarking` repo under `argoproj-labs` and add the authors of this proposal as maintainers. +2. Create a set of key scalability factors to use as testing parameters. For example: + 1. Number of Applications. + 2. Number of resources managed by an Application. + 3. Number of resources in a cluster. + 4. The size of the resources in a cluster and managed by an Application. + 5. Churn rate for resources in the cluster (how often resources change). + 6. Number of clusters. + 7. Number of repositories being monitored. + 8. Size of the repositories. + 9. The tooling (e.g., directory/raw manifests, Helm, Kustomize). +3. Determine the metrics that reflect limitations in scalability factors. + 1. Application sync time for x number of apps + 2. Emptying the queues (app_reconciliation_queue, app_operation_processing_queue) +4. Create automated testing procedures for Argo CD that take the key scalability factors as testing parameters. +5. Test the default installation of Argo CD to determine the limit based on the key scalability factors. +6. Create test scenarios that reflect the common topologies (Argo CD 1-1 with clusters, Argo CD 1-many with clusters). +7. Determine the thresholds for the metrics identified earlier to capture when performance is being impacted. + 1. Contribute back Grafana thresholds and alerts for Prometheus + +### Use cases +Each use case will cover a specific topology with N permutations based on the key scalability factors. They will be measured using the metrics given in the proposal. + +We intend to focus on two key topologies: one Argo CD per cluster and one Argo CD for all remote clusters. All other variations are an extension of these. + +#### Topology 1: One Argo CD per cluster. +The exact key scalability factors used in each permutation will be determined once we get to the testing. + +#### Topology 2: One Argo CD for all remote clusters. +This will capture the impact of network throughput on performance. + +#### Topology 3: One Namespaced Argo CD. +This instance will only manage namespace-level resources to determine the impact of monitoring cluster-scoped resources (related to the effect of resource churn in the cluster). + +### Implementation Details/Notes/Constraints [optional] +There is already some [tooling in the Argo CD repository](https://github.com/argoproj/argo-cd/pull/8037/files) for scalability testing. We plan to build on the existing effort and further push the boundaries of testing it. + +* Automatically set up supporting tooling for capturing metrics (Grafana, Prometheus) +* Use a local Gitea in the cluster to support many repositories used in testing, and avoid performance variance by depending on the performance of an external git SaaS (ie GitHub) +* Simulate the cluster and nodes using vcluster or kwok, in addition to using a cloud provider with a real cluster fleet. + * The simulated clusters and nodes are intended to make the testing accessible, but ultimately the infrastructure should be easily changed to test more realistic scenarios. Once the benchmarking tooling is functional, we can determine if the simulated components skew the results. + +Once we have the benchmarking tooling, we can determine if the simulated components skew the results compared to the real world. + +AWS intends to provide the infrastructure required to benchmark large-scale scenarios. + +### Security Considerations +There is no intention to change the security model of Argo CD and therefore this project has no direct security considerations. + +### Risks and Mitigations + +## Consider including folks that also work outside your immediate sub-project. + +## Drawbacks + +## Alternatives +* Implementing Argo CD into an environment than waiting for scaling issues to arise. Monitoring the metrics to understand what the limitations are to address them. Using arbitrary resource allocation and replica counts to avoid running into limitations. diff --git a/docs/proposals/applicationset-plugin-generator.md b/docs/proposals/applicationset-plugin-generator.md new file mode 100644 index 0000000000000..616ef13efcd2b --- /dev/null +++ b/docs/proposals/applicationset-plugin-generator.md @@ -0,0 +1,216 @@ +--- +title: applicationset-plugin-generator +authors: + - "@binboum" + - "@scrocquesel" +sponsors: + - TBD +reviewers: + - TBD +approvers: + - "@alexmt" + - TBD + +creation-date: 2022-03-21 +last-updated: 2022-03-21 +--- + +# ApplicationSet `plugin` generator + +Provide a generator that request its values through a RPC call. + +## Summary + +ApplicationSet generators are useful for modeling templates using external data sources to deploy applications. + +Today, generators have been developed based on the needs of the community, and when a new need arises, it's necessary to modify the Appset codebase. + +The proposal here is to have a "plugin" generator that would allow extending the codebase according to specific needs, without having to modify it directly. + +## Motivation + +Using the current generators, we sometimes encounter a need that arises, which may or may not be useful for the community. In such cases, several procedures need to be undertaken to make the modification, and sometimes it may be rejected because it's not in everyone's interest. + +The plugin approach also reduces the burden on community developers by externalizing feature requests into plugins that are outside the Appset controller's scope. From a security and scalability perspective, this can be advantageous. + +With this approach, it becomes possible to offer a catalog of plugins and encourage people with specific needs to develop standalone plugins that are independent of the controller's codebase. + +### Goals + +Empowering community developers to develop and use plugins that extend the list of generators can be a significant advantage. It would be possible to offer a page listing plugins maintained by the community, which can help promote the development of a rich ecosystem of plugins for various use cases. This can enhance the overall user experience by providing more options for generating application templates. + +Additionally, allowing developers to create plugins and share them with the community can foster innovation and encourage experimentation with new features and functionalities. It can also reduce the workload on the Appset development team, enabling them to focus on core features and functionalities. + +Overall, giving autonomy to community developers through plugins is a practical way to enhance the Appset platform and provide more value to users. + +### Non-Goals + +The concept of the plugin should not undermine the spirit of GitOps by externalizing data outside of Git. The goal is to be complementary in specific contexts. + +For example, when using one of the PullRequest generators, it's impossible to retrieve parameters related to the CI (only the commit hash is available), which limits the possibilities. By using a plugin, it's possible to retrieve the necessary parameters from a separate data source and use them to extend the functionality of the generator. This approach allows for greater flexibility and can help overcome limitations imposed by GitOps. + +Overall, the use of plugins should be considered as a way to enhance the capabilities of existing tools and processes rather than as a replacement for them. By leveraging plugins, developers can take advantage of the strengths of different tools and technologies, resulting in a more robust and flexible development process. + +## Proposal + +### Add a new `generator` plugin + +``` +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: fb-plugin + namespace: argo-system +spec: + generators: + - plugin: + configMapRef: fb-plugin + name: feature-branch-plugin + params: + repo: "my-repo" + branch: "my-branch" + requeueAfterSeconds: 10 + template: +... +``` + +### Add a configMap to configure the plugin + +The configMap name must match the configMapRef value in the plugin configuration. The configMap must be in the namespace of argo. + +``` +apiVersion: v1 +kind: ConfigMap +metadata: + name: fb-plugin + namespace: argo-system +data: + token: $plugin.myplugin.token # Alternatively $:plugin.myplugin.token + baseUrl: http://myplugin.plugin.svc.cluster.local +``` + +- token is used a bearer token in the RPC request. It could be a [sensitive reference](https://argo-cd.readthedocs.io/en/stable/operator-manual/user-management/#sensitive-data-and-sso-client-secrets). + +### Reconciliation logic + +Here is a diagram describing what the plugin generator should do to get the params to return: + +```mermaid +sequenceDiagram + alt generator is plugin + Generator->>K8S: Get configmap {configMapRef} + K8S-->>Generator: (url,token) + Generator->>Plugin endpoint: POST {url}/v1/generator.getParams
Authorization: Bearer {token}
Content-Type: application/json
{params} + Plugin endpoint-->>Generator: []map{string}interface{} + end +``` + + +### Use cases + +#### Use case 1: +As a user, I would like to enrich PullRequest generator params with digests of images generated by the pull request CI pipeline. + +I could define a generator matrix like + +```yaml + generators: + - matrix: + generators: + - pullRequest: + github: + owner: binboum + repo: argo-test + labels: + - preview-matrix + tokenRef: + secretName: github-secret + key: token + - plugin: + configMapRef: cm-plugin + name: plugin-matrix + params: + repo: "argo-test" + branch: "{{.branch}}" +``` + +When pullRequest returns a new PR matching my labels, the plugin will be called with the branch name and would return a set of digests like + +```json +[ + { + "digestFront": "xxxxxxxx", + "digestBack": "xxxxxxxx", + } +] +``` + +Values can then be used in the template section : + +```yaml + template: + metadata: + name: "fb-matrix-{{.branch}}" + spec: + source: + repoURL: "git@github.com:binboum/argo-test.git" + targetRevision: "HEAD" + path: charts/app-client + helm: + releaseName: feature-test-matrix-{{.branch}} + valueFiles: + - values.yaml + values: | + front: + image: registry.my/argo-test/front:{{.branch}}@{{ .digestFront }} + back: + image: registry.my/argo-test/back:{{.branch}}@{{ .digestBack }} + destination: + server: https://kubernetes.default.svc + namespace: "{{.branch}}" +``` + +### Detailed examples + +### Security Considerations + +* Plugin server only has access to the params content. When deployed outside of the applicationset controller pod, operator must ensure the communication between applicationset controller and the plugin server is properly secured (https/network policy...). A few authentication mechanism are handled to help the plugin server authenticate the request. +* For now, the response payload is considered trusted and returned params are used as-is upstream + +### Risks and Mitigations + +TBD + +### Upgrade / Downgrade Strategy + +On the evolution of the plugin, and calls : + +The RPC method is standardized with a versioning system, which allows for a version parameter to be included in the API call. This makes it possible to avoid breaking changes in case of architecture changes in the future. + +Thought that the contract interface with the plugin server is kept simple to reduce future changes and breaking changes + +## Drawbacks + +No idea + +## Alternatives + +1. A design similar to Argo Workflow executor plugin : + + ``` + generators: + - plugin: + hello: {} + ``` + + A set of ConfigMaps or a specific CRDs to express configuration of the plugin endpoint would be walk by ApplicationSet server. For each configuration, call the plugin endpoint with the content of plugin until one return a valid response. + + Reconciliation should be fast as fast as possible and trying out every endpoint to figure out which one is able to handle the plugin payload could induce a lot of delay. + + Configuration rely on implicit and weakly typed convention which make the usage of the plugin less self documented. + +2. Plugin server as defacto sidecars + + Some magic could have inject a container image for the plugin in the ApplicationSet controller in a similar way, Argo Workflow does when creating a pod to execute a job. + + Require an external controler or manual configuration. The plugin would not scale independently of the ApplicationSet controller. \ No newline at end of file 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.md b/docs/proposals/feature-bounties.md new file mode 100644 index 0000000000000..7d8eb02b33804 --- /dev/null +++ b/docs/proposals/feature-bounties.md @@ -0,0 +1,50 @@ +--- +title: Offering Feature Bounties (Experimental) +authors: + - "@crenshaw-dev" + - "@todaywasawesome" +sponsors: + - "@jannfis" +reviewers: + - TBD +approvers: + - TBD + +creation-date: 2023-06-27 +--- +# Offering Feature Bounties (Experimental) + +## Summary +We'd like to have the ability to offer monetary rewards for significant features to be added to Argo. + +## Motivation +The Argo Project is driven by community contributions and in shared trust with maintainer companies. Sometimes there are important features worth investing in that represent substantial work and are tougher, or take longer to implement. + +By providing a financial incentive, we can spur additional development from the community and indepdent contributors. + +## Proposal +Add the ability to mark a proposal with a bounty and a specific amount. When a PR is successfully merged, release payment to the PR author(s). + +This proposal is experimental, meaning after trying a single bounty, we will review as a project and decide if we would like to continue this program. Accepting this proposal only constitutes the program for a single bounty as an experiment. + +### Guidelines and Rules + +#### Creating a Bounty +A bounty is a special proposal created under `docs/proposals/feature-bounties`. + +* A bounty proposal may only be created by an existing Argo maintainer. +* The proposal document must be reviewed in regular maintainer meetings and an invitation for feedback will provide 7-days to comment. +* Bounty should have approval with [lazy-consensus](https://community.apache.org/committers/lazyConsensus.html) +* Once a bounty is created, they must be honored. +* Bounty progress will be tracked in a GitHub issue linked in the proposal. +* Creating a bounty requires the funds be available and not already committed elsewhere. + +#### Claiming a Bounty +* Argo will pay out bounties once a pull request implementing the requested features/changes/fixes is merged. +* A bounty is limited to a single successful PR. +* Those interested in working on the bounty are encouraged to comment on the issue, and users may team up to split a bounty if they prefer but collaboration is not required and users should not shame eachother for their preferences to work alone or together. +* A comment of interest does not constitute a claim and will not be treated as such. +* The first pull request submitted that is ready for merge will be reviewed by maintainers. Maintainers will also consider any competing pull requests submitted within 24-hours. We expect this will be a very rare circumstance. If multiple, high-quality, merge ready pull requests are submitted, 3-5 Approvers for the sub-project will vote to decide the final pull request merged. + +### Funding +The Argo Project has a small amount of funds from HackerOne bounties that can provide for a few feature bounties. \ 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-oci-support.md b/docs/proposals/native-oci-support.md new file mode 100644 index 0000000000000..7ec0053729c2e --- /dev/null +++ b/docs/proposals/native-oci-support.md @@ -0,0 +1,135 @@ +--- +title: Argo CD first-class OCI support +authors: + - "@sabre1041" + - "@crenshaw-dev" + - "@todaywasawesome" + +sponsors: + - TBD +reviewers: + - "@alexmt" +approvers: + - "@alexmt" + +creation-date: 2023-05-09 +--- + +# Argo CD first-class OCI support + +Storing and retrieving manifests within in OCI registries + +## Summary + +Currently, Argo CD supports obtaining manifests from either a Git repository, a Helm chart repository, or a Helm chart stored within an OCI registry. Given that OCI registries are more frequently being used to store content aside from container images, introduce a mechanism for storing and retrieving manifests that can be used by any of the existing supported tools in any of the supported methods of representing assets that are to be applied to a Kubernetes environment. + + +## Motivation + +The industry is seeing a rapid adoption of OCI Artifacts as a method for storing and retrieving content. Adding support for sourcing resources stored in OCI artifacts not only provides immediate benefits, but opens up additional possible integrations in the future. + +**Dependency Reduction** + + At the present time, a user must have access to either a Git repository, or a remote Helm chart repository. Most users or enterprise organizations already have access to an OCI registry as it represents the primary source of image related content within a Kubernetes environment. By sourcing assets from OCI registries, no additional infrastructure is required in order to store a variety of content types simplifying the set of requirements in order to begin to fully leverage the capabilities of Argo CD. + +**Market Relevance** + +Argo CD continues to be one of the most popular GitOps tools in the industry. As the industry continues to evolve, other tools within the GitOps market have already began to adopt OCI artifacts as a source for storing and retrieving GitOps resources. + +### Goals + +* Enable the retrieval of resources stored as artifacts in OCI registries that are formatted in any of the supported options (Kustomize, Jsonnet, Helm, plain-manifest, CMPs, etc) +* Define a format for storing resources that can be processed by Argo CD as an OCI artifact including the composition and [Media Type(s)](https://github.com/opencontainers/image-spec/blob/main/media-types.md) +* Support the retrieval of artifacts from OCI registries using custom / self signed TLS certificates. +* Support the retrieval of artifacts from OCI registries requiring authentication. + +### Non-Goals + +* CLI Integration to package and publish resources in a format for storage in an OCI registry +* Attach metadata to OCI artifact manifest to provide additional details related to the content (such as original Git source [URL, revision]) + +## Proposal + +This is where we get down to details of what the proposal is about. + +### Use cases + +Add a list of detailed use cases this enhancement intends to take care of. + +#### Publishing and retrieval of content from OCI registries: + +As a user, I would like to make use of content that is represented by any of the supported options (Kustomize, Jsonnet, Helm, plain-manifest, etc) or those that could be consumed using a Config Management Plugin from an OCI registry. + +#### Authenticating to OCI registries: + +As a user, I would like to enforce proper security controls by requiring authentication to an OCI registry and configure Argo CD to be able to interact with this registry. + +#### CLI Integration: + +As a user, I would like the ability to produce, store and retrieve resources (pull/push) in a OCI registry using the Argo CD CLI. + +### Implementation Details/Notes/Constraints + +The Argo CD repo-server currently maintains two types of clients - Helm and git. By adding a third client, and invoking it in the same places as the other two, we can support OCI artifacts. + +It seems likely that we should create a new, common interface to represent all three clients. Then we can instantiate the client we need, toggling on whatever value in the repo config determines what kind of repo we're fetching from. + +#### Format of OCI Artifact + +An OCI artifact can contain any type of binary content. It is important that the content be formatted in a manner that can be consumed by Argo CD. + +#### Content + +Resources that is consumed by Argo CD can be represented by a series of files and folders. To be stored within an OCI artifact, these assets are stored within a compressed tar archive (.tar.gz) OCI layer. The [OCI Image Specification](https://specs.opencontainers.org/image-spec/) allows for metadata to be added through the use of annotations to provide attribute based details describing the included content. This level of detail is important as it satisfies many of the existing capabilities of Argo CD for tracking content, such as Git repository URL, branch name/revision. + + +#### Media Types + +The [OCI Image Specification](https://specs.opencontainers.org/image-spec/) makes extensive use of Media Types to identity the format of content. To provide not only a way that signifies the content of the OCI artifact contains Argo CD manifests, but to define the structure of the content. An understanding of the composition and requirements enable a broad ecosystem of tooling that can be used to produce and consume Argo CD resources within OCI registries. + +Two new Media Types will be used for this purpose as defined below: + +* `application/vnd.cncf.argoproj.argocd.content.v1.tar+gzip` - Primary asset stored within the OCI artifact containing a gzip compressed tar archive of Argo CD resources. Further details are outlined in the prior section. +* `application/vnd.cncf.argoproj.argocd.config.v1+json` - An [OCI Image Configuration](https://specs.opencontainers.org/image-spec/config/) + + +### Detailed examples + + +### Security Considerations + +The direct integration with an external endpoint from the core subsystem of Argo CD introduces several considerations as it relates to security. It is worthy to note that Argo CD currently does support sourcing Helm charts that are stored within OCI registries. However, this interaction is performed by Helm and its underlying library, [ORAS](https://oras.land), and not Argo CD itself. Capabilities included within this proposal can make use of the same libraries to facilitate the interaction. + +#### Credentials + +Security controls may be enforced within the OCI registry to enforce that clients authenticate. The introduction of additional mechanisms to authenticate against target systems is outside the scope of this proposal. However, an integration with existing capabilities and features, such as sourcing from _repository_ credentials is required. + + +### Risks and Mitigation's + +#### Overlap with existing Helm OCI integration + +Argo CD already includes support for sourcing Helm Charts from OCI registries and the retrieval is delegated to functionality provided by Helm. Considerations must be taken into account to determine whether the intent by the end user is to consume an OCI artifact containing Argo CD related resources or a Helm chart. One such method for addressing this concern is to inspect the `mediaType` of the OCI artifact. + + +### 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? + +## 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 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. 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/proposals/rebalancing-clusters-across-shards-dynamically.md b/docs/proposals/rebalancing-clusters-across-shards-dynamically.md new file mode 100644 index 0000000000000..63ed973004cf5 --- /dev/null +++ b/docs/proposals/rebalancing-clusters-across-shards-dynamically.md @@ -0,0 +1,142 @@ +--- +title: Neat-enhancement-idea +authors: + - "@ishitasequeira" # Authors' github accounts here. +sponsors: + - TBD # List all interested parties here. +reviewers: + - "@alexmt" + - TBD +approvers: + - "@alexmt" + - TBD + +creation-date: yyyy-mm-dd +last-updated: yyyy-mm-dd +--- + +# Neat Enhancement Idea + +Rebalance clusters across shards automatically on changes to the number of available shards. + + +## Open Questions [optional] + +This is where to call out areas of the design that require closure before deciding to implement the +design. + + +## Summary + +Current implementation of sharding uses StatefulSet for the application controller and the goal is to move towards an agile stateless Deployment. Although the application controller does not have any state to preserve, stateful sets were used to get predictable hostnames and the serial number in the hostname was used to get the shard id of a particular instance. Using StatefulSet has the following limitations: + +Any change done to the StatefulSet would cause all the child pods to restart in a serial fashion. This makes scaling up/down of the application controller slow as even existing healthy instances need to be restarted as well. +Scaling up or down happens one at a time. If there are 10 instances and if scaled to 20, then the scaling happens one at a time, causing considerable delay for the scaling to complete. + +Each shard replica knows about the total number of available shards by evaluating the environment variable ARGOCD_CONTROLLER_REPLICAS, which needs to be kept up-to-date with the actual number of available replicas (shards). If the number of replicas does not equal the number set in ARGOCD_CONTROLLER_REPLICAS, sharding will not work as intended, leading to both, unused and overused replicas. As this environment variable is set on the StatefulSet and propagated to the pods, all the pods in the StatefulSet need to be restarted in order to pick up the new number of total shards. + +The current sharding mechanism relies on predictable pod names for the application controller to determine which shard a given replica should impersonate, e.g. the first replica of the StatefulSet (argocd-application-controller-0) will be the first shard, the second replica (argocd-application-controller-1) will be the second and so forth. + +## Motivation + +If the number of available shards is changed (i.e. one or more application controller replicas are added or removed), all pods in the statefulset have to be restarted so that the managed clusters are redistributed over the available shards. Additionally, the application controller workload is deployed as a StatefulSet, which is not intended for dynamic horizontal scaling. + +### Goals + +- Improve the application controller’s ability to scale horizontally with a growing number of clusters +- Remove the need to run application controller as a StatefulSet workload + +### Non-Goals + +- Expand the scope of sharding to other assets than clusters (e.g. applications) +- Make a single shard highly available (e.g. by having 2 or more replicas by shard) + +## Proposal + +### Why use Deployments instead of StatefulSet: +StatefulSet is a Kubernetes resource that manages multiple pods that have unique identities, and are not interchangeable (unlike a regular Kubernetes Deployment, in which pods are stateless and can be destroyed and recreated as often as needed). + +Stateless applications scale horizontally very easily as compared to stateful applications due to the fact that infrastructure allows adding as many computing resources as needed. Changing the StatefulSet to Deployments for Application Controller will allow us to dynamically scale the replicas without restarting existing application controller pods. Also, the shard to application controller assignment would help in making sure the shards are scaled and distributed across the available healhty replicas of application controllers. + +### Distributing shards among Application Controllers: + +Inorder to be able to accurately know which shards are being managed by which application-controller, especially in scenarios of redistribution of load, addition/removal of `application controller`, etc., we would need to have a mechanism to assign clusters to the shards. + +In most scenarios, the service account used by the application controller has read access to all the resources in the cluster. Thus, instead of setting the environment variable ARGOCD_CONTROLLER_REPLICAS representing the number of replicas, the number of replicas can be read directly from the number of healthy replicas of the application controller deployment. + +For other scenarios, some users install controller with only `argocd-application-controller-role` role and use it to manage remote clusters only. In this case, we would need to update the `argocd-application-controller-role` role and allow controller inspect it's own deployment and find out the number of replicas. + +The application controllers will claim one of the available shards by checking which shard is not present in the ConfigMap or is assigned to an unhealthy controller. We will store the assignment list of Application Controller to Shard in ConfigMap. The mapping of Application Controller to Shard will store the below information: + +* Name/Id of the shard +* Name of the Application Controller currently managing the shard +* Last time of successful update to ConfigMap (Heartbeat) + +The mapping will be updated in ConfigMap every X (heartbeat interval) seconds with the help of heartbeat process performed by every application controller. If the heartbeat was not performed by the application controller for a certain time, the application controller is assumed to be unhealthy and the number of healthy/managed shards would be reduced, that is, the number of healthy replicas of the application controller deployment changes. + +The heartbeat interval will be a configurable parameter initialized while setting up the application controller. This way, users will be able to control the frequency at which they want the heartbeat process to take place. + +As part of the readiness probe, we will also add a check whether application controller was able to claim a shard successfully or not. If the shard claim failed, the readiness probe will fail marking the controller as unhealthy. Anytime the number of healthy replicas of application controllers is different from the number of application controllers to shard mappings, we would re-distribute the clusters among the healthy replicas again. We can summarize the above statement using the below formula: + +``` +Number of Replicas ≠ Count of {Application Controller, Shard} mapping +``` + +The below logic can be used to perform application controller to shard assignment: + +1) If a new application controller is added, that is, a new shard is added, we would perform the re-distribution of clusters among the shards with the existing sharding algorithm being used. + +2) In scenarios when one of the application controllers is identified to be unhealthy, we will not trigger the re-ditribution of clusters across shards. The new instance of the application controller will claim this unassigned shard and start managing the shard. + +How will this work? +* The application controller will query the ConfigMap for the status of all the application controllers and last updated heartbeat timestamps. +* It will check if any application controller is flagged as Unhealthy or has not updated its status in ConfigMap during the heartbeat process for a certain period of time. +* If the status for an application controller was already flagged as Unhealthy, we will not re-trigger the redistribution of clusters across healthy shards. The new application controller will come online and try to claim this unassigned shard. +* If the status is not flagged and an application controller has not updated the last active timestamp in a long time, then we mark the Application Controller as Unhealthy and unassign the shard in the ConfigMap. + +*Note:* We will continue to use the cluster to shard assignment approach being used today. + +### Pros +* Every Application Controller would be able to take action on finding the distribution of load. +* Every Application Controller will monitor the status of Unhealthy shard and would be able to take action or flag for action. + +### Cons + +* ~~Possibility of race conditions while flagging the shard as Unhealthy during the heartbeat process. Although this can be handled using the [distributed locks](https://redis.io/docs/manual/patterns/distributed-locks/) in Redis.~~ +As we are using ConfigMap, this Con get's removed. Kubernetes would give conflict errors in case multiple edits are tried on the ConfigMap at the same time. We can leverage this error messages to avoid race conditions. + +* ~~In scenarios when Redis becomes unavailable, the heartbeat mechanism will pause working till the redis comes back online again. This will also pause the dynamic redistribution of clusters till Redis comes back online. The redistribution of clusters will be triggered again when Redis comes back online.~~ We would not see this issue by using ConfigMap instead of Redis. + + +### Security Considerations + +* This would be a breaking change of converting StatefulSets to Deployments. Any automation done by customers which is based on the assumption that the controller is modelled as a StatefulSet would break with this change. + +* ~~We would rely on Redis to store the current Application Controller to Shard mapping. In case the Redis is not available, it would not affect the regular working of ArgoCD. The dynamic distribution of clusters among healthy shards would stop working with the heartbeat process till Redis comes back up online, but the application controllers will continue managing their workloads.~~ We would not rely on Redis by using ConfigMap avoiding this issue. + + +### Upgrade / Downgrade Strategy + +* Working ArgoCD itself should not affected. An initial restart of all the application controller pods is expected when we switch from StatefulSet to Deployment or vice-versa. + +* There would be some initial delays in the reconciliation process during the transistion from StatefulSet to Deployment. If someone is not using sharding at all, they should not face any issues. + +## Alternatives + +An alternative approach would be to use Leader Election strategy. By implementing leader election, one of the healthy application controllers will be appointed as leader. The leader controller will be responsible for assigning clusters to the shards and balancing load across the shards. + +The leader controller will continue sending heartbeats to every replica controller and monitor the health of the controllers. In case one of the replica controllers crashes, the leader will distribute the shards managed by the unhealthy replica among the healthy replicas. + +If the leader goes down, the leader election process will be initiated among the healthy candidates and one of the candidates will be marked as leader who will perform the heartbeat process and redistribution of resources. + +One of the possible examples for selecting the leader is by checking the load handled by each healthy candidate and selecting the candidate which has the least load / number of resources running on it. + +### Pros of Leader Election + +* We can refrain from performing multiple calls to ConfigMap about the load and status of the shards and store it in a local cache within the leader while updating data in ConfigMap on a timely manner (for e.g. every 10 mins). +* Single leaders can easily offer clients consistency because they can see and control all the changes made to the state of the system. + + +### Cons of Leader Election +* A single leader is a single point of failure. If the leader becomes bad, that is, does not distribute clusters properly across shards, it is very difficult to identify or fix the bad behavior and can become a single point of failure +* A single leader means a single point of scaling, both in data size and request rate. When a leader-elected system needs to grow beyond a single leader, it requires a complete re-architecture. diff --git a/docs/proposals/respect-rbac-for-resource-exclusions.md b/docs/proposals/respect-rbac-for-resource-exclusions.md new file mode 100644 index 0000000000000..fb4227638b6e7 --- /dev/null +++ b/docs/proposals/respect-rbac-for-resource-exclusions.md @@ -0,0 +1,74 @@ +--- +title: Respect RBAC for Resource Inclusions/Exclusions + +authors: +- "@gdsoumya" +- "@alexmt" + +sponsors: +- TBD + +reviewers: +- @jannfis + +approvers: +- @jannfis + +creation-date: 2023-05-03 + +--- + +# Enhancement Idea + +This is a proposal to provide the ability to configure argocd controller, to respect the current RBAC permissions +when handling resources besides the already existing resource inclusions and exclusions. + +## Summary + +Argo CD administrator will be able to configure in `argocd-cm`, whether to enable or disable(default) the feature where the controller will +only monitor resources that the current service account allows it to read. + +## Motivation + +Some users restrict the access of the argocd to specific resources using rbac and this feature will enable them to continue +using argocd without having to manually configure resource exclusions for all the resources that they don't want argocd to be managing. + +## Proposal + +The configuration for this will be present in the `argocd-cm`, we will add new boolean field `resource.respectRBAC` in the +cm which can be set to `true` to enable this feature, by default the feature is disabled. + +For the implementation there are 3 proposals : + +1. Modify `gitops-engine` pkg to make a `SelfSubjectAccessReview` request before adding any resource to the watch list, in this approach we are making an extra + api server call to check if controller has access to the resource, this does increase the no. of kubeapi calls made but is more accurate. +2. Modify `gitops-engine` pkg to check for forbidden/unauthorized errors when listing for resources, this is more efficient approach as the + no. of kubeapi calls made does not change, but there is a chance of false positives as similar errors can be returned from kubeapi server or env specific proxies in other situations +3. Combine approaches 1 and 2, in this controller will check the api response for the list call, and if it receives forbidden/unauthorized it will make the `SelfSubjectAccessReview` call. + This approach is accurate and at the same time, only makes extra api calls if the list calls fail in the first place. + +In all solutions, once controller determines that it does not have access to the resource it will stop monitoring it. + +### Implementation decision + +It was decided that we will go with approach 3 from the above list, but instead of a boolean flag we will have the `resource.respectRBAC` take 3 configuration options for the users : + - `strict` : This will perform both the checks i.e. whether the list call response is forbidden/unauthorized and if it is make the `SelfSubjectAccessReview` call to confirm. + - `normal` : This will only check whether the list call response is forbidden/unauthorized and skip `SelfSubjectAccessReview` call. + - unset/empty : This will disable the feature and controller will continue to monitor all resources. + +NOTE: By default `resource.respectRBAC` will be unset or `""` which disables the feature + +Users who are okay with an increase in kube api server calls can opt for strict option while users who are concerned with higher api calls can compromise on the accuracy and opt for the normal option. + +## Security Considerations and Risks + +There are no particular security risks associated with this change, this proposal rather improves the argocd controller +to not access/monitor resources that it does not have permission to access. + +## Upgrade / Downgrade Strategy + +There is no special upgrade strategy needed, all existing argocd configmaps will continue to work +and old configs without the `resource.respectRBAC` config will cause no change in argocd controllers behavior. + +While downgrading to older version, if the user had configured `resource.respectRBAC` previously this would be ignored completely +and argocd would revert to its default behavior of trying to monitor all resources. \ No newline at end of file diff --git a/docs/proposals/sync-timeout.md b/docs/proposals/sync-timeout.md new file mode 100644 index 0000000000000..5d8e5c3b3d86d --- /dev/null +++ b/docs/proposals/sync-timeout.md @@ -0,0 +1,126 @@ +--- +title: Neat-enhancement-idea +authors: + - "@alexmt" +sponsors: + - "@jessesuen" +reviewers: + - "@ishitasequeira" +approvers: + - "@gdsoumya" + +creation-date: 2023-12-16 +last-updated: 2023-12-16 +--- + +# Sync Operation Timeout & Termination Settings + +The Sync Operation Timeout & Termination Settings feature introduces new sync operation settings that control automatic sync operation termination. + +## Summary + + +The feature includes two types of settings: + +* The sync timeout allows users to set a timeout for the sync operation. If the sync operation exceeds this timeout, it will be terminated. + +* The Termination settings are an advanced set of options that enable terminating the sync operation earlier when a known resource is stuck in a +certain state for a specified amount of time. + +## Motivation + +Complex synchronization operations that involve sync hooks and sync waves can be time-consuming and may occasionally become stuck in a specific state +for an extended duration. In certain instances, these operations might indefinitely remain in this state. This situation becomes particularly inconvenient when the +synchronization is initiated by an automation tool like a CI/CD pipeline. In these scenarios, the automation tool may end up waiting indefinitely for the +synchronization process to complete. + +To address this issue, this feature enables users to establish a timeout for the sync operation. If the operation exceeds the specified time limit, +it will be terminated, preventing extended periods of inactivity or indefinite waiting in automated processes. + +### Goals + +The following goals are intended to be met by this enhancement: + +#### [G-1] Synchronization timeout + +The synchronization timeout feature should allow users to set a timeout for the sync operation. If the sync operation exceeds this timeout, it will be terminated. + +#### [G-2] Termination settings + +The termination settings would allow users to terminate the sync operation earlier when a known resource is stuck in a certain state for a specified amount of time. + +## Proposal + +The proposed additional synchronization settings are to be added to the `syncPolicy.terminate` field within the Application CRD. The following features are to be added: + +* `timeout` - The timeout for the sync operation. If the sync operation exceeds this timeout, it will be terminated. +* `resources` - A list of resources to monitor for termination. If any of the resources in the list are stuck in a + certain state for a specified amount of time, the sync operation will be terminated. + +Example: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: guestbook +spec: + ... # standard application spec + + syncPolicy: + terminate: + timeout: 10m # timeout for the sync operation + resources: + - kind: Deployment + name: guestbook-ui + timeout: 5m # timeout for the resource + health: Progressing # health status of the resource +``` + +### Use cases + +Add a list of detailed use cases this enhancement intends to take care of. + +#### Normal sync operation: +As a user, I would like to trigger a sync operation and expect it to complete within a certain time limit. + +#### CI triggered sync operation: +As a user, I would like to trigger a sync operation from a CI/CD pipeline and expect it to complete within a certain time limit. + +#### Preview Applications: +As a user, I would like to leverage ApplicationSet PR generator to generate preview applications and expect the auto sync operation fails automatically +if it exceeds a certain time limit. + +### Implementation Details/Notes/Constraints [optional] + +The application CRD status field already has all required information to implement sync timeout. + +* Global sync timeout: only the operation start time is required to implement this functoinality. It is provided be the `status.operationState.startedAt` field. +* Resources state based termination. This part is a bit more complex and requires information about resources affected/created during the sync operation. Most of +the required information is already available in the Application CRD status field. The `status.operationState.syncResult.resources` field contains a list of resources +affected/created during the sync operation. Each `resource` list item includes the resource name, kind, and the resource health status. In order to provide accurate +duration of the resource health status it is proposed to add `modifiedAt` field to the `resource` list item. This field will be updated every time the resource health/phase +changes. + +### Security Considerations + +Proposed changes don't expand the scope of the application CRD and don't introduce any new security concerns. + +### Risks and Mitigations + +The execution of a synchronization operation is carried out in phases, which involve a series of Kubernetes API calls and typically take up to a few seconds. +There is no easy way to terminate the operation during the phase. So the operation might take few seconds longer than the specified timeout. It does not seems +reasonable to implement a more complex logic to terminate the operation during the phase. So it is proposed to just document that the operation might be terminated +few seconds after the timeout is reached. + +### Upgrade / Downgrade Strategy + +The proposed changes don't require any special upgrade/downgrade strategy. The new settings are optional and can be used by users only if they need them. + +## Drawbacks + +Slight increase of the application syncrhonization logic complexity. + +## Alternatives + +Rely on the external tools to terminate the sync operation. For example, the CI/CD pipeline can terminate the sync operation if it exceeds a certain time limit. \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt index f83fae49f0e7b..d350ac4870ee2 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,6 +1,9 @@ -mkdocs==1.2.3 +mkdocs==1.3.0 +# Strict mode has been disabled in latest versions of mkdocs-material. +# Thus pointing to the older version of mkdocs-material. mkdocs-material==7.1.8 markdown_include==0.6.0 -pygments==2.7.4 +pygments==2.15.0 jinja2==3.0.3 -markdown==3.3.7 \ No newline at end of file +markdown==3.3.7 +pymdown-extensions==10.2.1 \ No newline at end of file diff --git a/docs/snyk/index.md b/docs/snyk/index.md index 520d2b224c90d..5f26934a1b4b4 100644 --- a/docs/snyk/index.md +++ b/docs/snyk/index.md @@ -13,64 +13,50 @@ recent minor releases. | | Critical | High | Medium | Low | |---:|:--------:|:----:|:------:|:---:| -| [go.mod](master/argocd-test.html) | 0 | 0 | 0 | 0 | -| [ui/yarn.lock](master/argocd-test.html) | 0 | 0 | 1 | 0 | -| [dex:v2.35.3](master/ghcr.io_dexidp_dex_v2.35.3.html) | 0 | 0 | 0 | 0 | -| [haproxy:2.6.2-alpine](master/haproxy_2.6.2-alpine.html) | 0 | 0 | 0 | 0 | -| [argocd:latest](master/quay.io_argoproj_argocd_latest.html) | 0 | 0 | 2 | 14 | -| [redis:7.0.7-alpine](master/redis_7.0.7-alpine.html) | 0 | 0 | 0 | 0 | +| [go.mod](master/argocd-test.html) | 0 | 0 | 9 | 0 | +| [ui/yarn.lock](master/argocd-test.html) | 0 | 0 | 0 | 0 | +| [dex:v2.38.0](master/ghcr.io_dexidp_dex_v2.38.0.html) | 0 | 0 | 2 | 1 | +| [haproxy:2.6.14-alpine](master/haproxy_2.6.14-alpine.html) | 0 | 1 | 3 | 1 | +| [argocd:latest](master/quay.io_argoproj_argocd_latest.html) | 0 | 0 | 8 | 14 | +| [redis:7.0.14-alpine](master/redis_7.0.14-alpine.html) | 0 | 0 | 2 | 1 | | [install.yaml](master/argocd-iac-install.html) | - | - | - | - | | [namespace-install.yaml](master/argocd-iac-namespace-install.html) | - | - | - | - | -### v2.6.0-rc4 +### v2.9.9 | | Critical | High | Medium | Low | |---:|:--------:|:----:|:------:|:---:| -| [go.mod](v2.6.0-rc4/argocd-test.html) | 0 | 0 | 0 | 0 | -| [ui/yarn.lock](v2.6.0-rc4/argocd-test.html) | 0 | 0 | 1 | 0 | -| [dex:v2.35.3](v2.6.0-rc4/ghcr.io_dexidp_dex_v2.35.3.html) | 0 | 0 | 0 | 0 | -| [haproxy:2.6.2-alpine](v2.6.0-rc4/haproxy_2.6.2-alpine.html) | 0 | 0 | 0 | 0 | -| [argocd:v2.6.0-rc4](v2.6.0-rc4/quay.io_argoproj_argocd_v2.6.0-rc4.html) | 0 | 0 | 2 | 14 | -| [redis:7.0.7-alpine](v2.6.0-rc4/redis_7.0.7-alpine.html) | 0 | 0 | 0 | 0 | -| [install.yaml](v2.6.0-rc4/argocd-iac-install.html) | - | - | - | - | -| [namespace-install.yaml](v2.6.0-rc4/argocd-iac-namespace-install.html) | - | - | - | - | +| [go.mod](v2.9.9/argocd-test.html) | 0 | 1 | 11 | 0 | +| [ui/yarn.lock](v2.9.9/argocd-test.html) | 0 | 0 | 0 | 0 | +| [dex:v2.37.0](v2.9.9/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 1 | 6 | 1 | +| [haproxy:2.6.14-alpine](v2.9.9/haproxy_2.6.14-alpine.html) | 0 | 1 | 3 | 1 | +| [argocd:v2.9.9](v2.9.9/quay.io_argoproj_argocd_v2.9.9.html) | 0 | 0 | 9 | 14 | +| [redis:7.0.11-alpine](v2.9.9/redis_7.0.11-alpine.html) | 1 | 1 | 6 | 1 | +| [install.yaml](v2.9.9/argocd-iac-install.html) | - | - | - | - | +| [namespace-install.yaml](v2.9.9/argocd-iac-namespace-install.html) | - | - | - | - | -### v2.5.7 +### v2.8.13 | | Critical | High | Medium | Low | |---:|:--------:|:----:|:------:|:---:| -| [go.mod](v2.5.7/argocd-test.html) | 0 | 0 | 4 | 0 | -| [ui/yarn.lock](v2.5.7/argocd-test.html) | 0 | 0 | 4 | 0 | -| [dex:v2.35.3](v2.5.7/ghcr.io_dexidp_dex_v2.35.3.html) | 0 | 0 | 0 | 0 | -| [haproxy:2.6.2-alpine](v2.5.7/haproxy_2.6.2-alpine.html) | 0 | 0 | 0 | 0 | -| [argocd:v2.5.7](v2.5.7/quay.io_argoproj_argocd_v2.5.7.html) | 0 | 0 | 2 | 14 | -| [redis:7.0.7-alpine](v2.5.7/redis_7.0.7-alpine.html) | 0 | 0 | 0 | 0 | -| [install.yaml](v2.5.7/argocd-iac-install.html) | - | - | - | - | -| [namespace-install.yaml](v2.5.7/argocd-iac-namespace-install.html) | - | - | - | - | +| [go.mod](v2.8.13/argocd-test.html) | 0 | 1 | 11 | 0 | +| [ui/yarn.lock](v2.8.13/argocd-test.html) | 0 | 0 | 0 | 0 | +| [dex:v2.37.0](v2.8.13/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 1 | 6 | 1 | +| [haproxy:2.6.14-alpine](v2.8.13/haproxy_2.6.14-alpine.html) | 0 | 1 | 3 | 1 | +| [argocd:v2.8.13](v2.8.13/quay.io_argoproj_argocd_v2.8.13.html) | 0 | 0 | 9 | 14 | +| [redis:7.0.11-alpine](v2.8.13/redis_7.0.11-alpine.html) | 1 | 1 | 6 | 1 | +| [install.yaml](v2.8.13/argocd-iac-install.html) | - | - | - | - | +| [namespace-install.yaml](v2.8.13/argocd-iac-namespace-install.html) | - | - | - | - | -### v2.4.19 +### v2.7.17 | | Critical | High | Medium | Low | |---:|:--------:|:----:|:------:|:---:| -| [go.mod](v2.4.19/argocd-test.html) | 0 | 0 | 4 | 0 | -| [ui/yarn.lock](v2.4.19/argocd-test.html) | 0 | 0 | 4 | 0 | -| [dex:v2.35.3](v2.4.19/ghcr.io_dexidp_dex_v2.35.3.html) | 0 | 0 | 0 | 0 | -| [haproxy:2.0.29-alpine](v2.4.19/haproxy_2.0.29-alpine.html) | 0 | 0 | 0 | 0 | -| [argocd:v2.4.19](v2.4.19/quay.io_argoproj_argocd_v2.4.19.html) | 0 | 0 | 2 | 14 | -| [redis:7.0.7-alpine](v2.4.19/redis_7.0.7-alpine.html) | 0 | 0 | 0 | 0 | -| [install.yaml](v2.4.19/argocd-iac-install.html) | - | - | - | - | -| [namespace-install.yaml](v2.4.19/argocd-iac-namespace-install.html) | - | - | - | - | - -### v2.3.13 - -| | Critical | High | Medium | Low | -|---:|:--------:|:----:|:------:|:---:| -| [go.mod](v2.3.13/argocd-test.html) | 0 | 0 | 4 | 0 | -| [ui/yarn.lock](v2.3.13/argocd-test.html) | 0 | 2 | 6 | 0 | -| [dex:v2.35.3](v2.3.13/ghcr.io_dexidp_dex_v2.35.3.html) | 0 | 0 | 0 | 0 | -| [haproxy:2.0.29-alpine](v2.3.13/haproxy_2.0.29-alpine.html) | 0 | 0 | 0 | 0 | -| [argocd-applicationset:v0.4.1](v2.3.13/quay.io_argoproj_argocd-applicationset_v0.4.1.html) | 0 | 4 | 38 | 29 | -| [argocd:v2.3.13](v2.3.13/quay.io_argoproj_argocd_v2.3.13.html) | 0 | 0 | 2 | 14 | -| [redis:6.2.8-alpine](v2.3.13/redis_6.2.8-alpine.html) | 0 | 0 | 0 | 0 | -| [install.yaml](v2.3.13/argocd-iac-install.html) | - | - | - | - | -| [namespace-install.yaml](v2.3.13/argocd-iac-namespace-install.html) | - | - | - | - | +| [go.mod](v2.7.17/argocd-test.html) | 0 | 0 | 9 | 0 | +| [ui/yarn.lock](v2.7.17/argocd-test.html) | 0 | 1 | 0 | 0 | +| [dex:v2.37.0](v2.7.17/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 1 | 6 | 1 | +| [haproxy:2.6.14-alpine](v2.7.17/haproxy_2.6.14-alpine.html) | 0 | 1 | 3 | 1 | +| [argocd:v2.7.17](v2.7.17/quay.io_argoproj_argocd_v2.7.17.html) | 0 | 0 | 12 | 19 | +| [redis:7.0.14-alpine](v2.7.17/redis_7.0.14-alpine.html) | 0 | 0 | 2 | 1 | +| [install.yaml](v2.7.17/argocd-iac-install.html) | - | - | - | - | +| [namespace-install.yaml](v2.7.17/argocd-iac-namespace-install.html) | - | - | - | - | diff --git a/docs/snyk/master/argocd-iac-install.html b/docs/snyk/master/argocd-iac-install.html index 08b5e4e70a09f..c063a06f7dae8 100644 --- a/docs/snyk/master/argocd-iac-install.html +++ b/docs/snyk/master/argocd-iac-install.html @@ -456,7 +456,7 @@

Snyk test report

-

January 22nd 2023, 12:17:21 am

+

March 24th 2024, 12:17:17 am (UTC+00:00)

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

Snyk test report

-
32 total issues
+
39 total issues
@@ -482,8 +482,54 @@

Snyk test report

+
+

Role or ClusterRole with dangerous permissions

+
+ +
+ high severity +
+ +
+ +
    +
  • + Public ID: SNYK-CC-K8S-47 +
  • + +
  • Introduced through: + [DocId: 16] + + rules[5] + + resources + +
  • + +
  • + Line number: 21035 +
  • +
+ +
+ +

Impact

+

Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

+ +

Remediation

+

Consider removing these permissions

+ + +
+
+ + + +
-

Role with dangerous permissions

+

Role or ClusterRole with dangerous permissions

@@ -494,7 +540,7 @@

Role with dangerous permissions

  • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
  • Introduced through: @@ -507,29 +553,29 @@

    Role with dangerous permissions

  • - Line number: 15177 + Line number: 20744

Impact

-

Using this role grants dangerous permissions

+

Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

Remediation

-

Consider removing this permissions

+

Consider removing these permissions


-

Role with dangerous permissions

+

Role or ClusterRole with dangerous permissions

@@ -540,7 +586,7 @@

Role with dangerous permissions

  • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
  • Introduced through: @@ -553,29 +599,29 @@

    Role with dangerous permissions

  • - Line number: 15254 + Line number: 20829

Impact

-

Using this role grants dangerous permissions

+

Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

Remediation

-

Consider removing this permissions

+

Consider removing these permissions


-

Role with dangerous permissions

+

Role or ClusterRole with dangerous permissions

@@ -586,7 +632,7 @@

Role with dangerous permissions

  • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
  • Introduced through: @@ -599,29 +645,29 @@

    Role with dangerous permissions

  • - Line number: 15282 + Line number: 20857

Impact

-

Using this role grants dangerous permissions

+

Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

Remediation

-

Consider removing this permissions

+

Consider removing these permissions


-

Role with dangerous permissions

+

Role or ClusterRole with dangerous permissions

@@ -632,42 +678,42 @@

Role with dangerous permissions

  • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
  • Introduced through: [DocId: 13] - rules[3] + rules[1] resources
  • - Line number: 15326 + Line number: 20887

Impact

-

Using this role grants dangerous permissions

+

Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

Remediation

-

Consider removing this permissions

+

Consider removing these permissions


-

Role with dangerous permissions

+

Role or ClusterRole with dangerous permissions

@@ -678,42 +724,42 @@

Role with dangerous permissions

  • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
  • Introduced through: [DocId: 13] - rules[1] + rules[3] resources
  • - Line number: 15308 + Line number: 20905

Impact

-

Using this role grants dangerous permissions

+

Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

Remediation

-

Consider removing this permissions

+

Consider removing these permissions


-

Role with dangerous permissions

+

Role or ClusterRole with dangerous permissions

@@ -724,7 +770,7 @@

Role with dangerous permissions

  • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
  • Introduced through: @@ -737,24 +783,24 @@

    Role with dangerous permissions

  • - Line number: 15342 + Line number: 20921

Impact

-

Using this role grants dangerous permissions

+

Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

Remediation

-

Consider removing this permissions

+

Consider removing these permissions


@@ -770,11 +816,11 @@

Container could be running with outdated image

  • - Public ID: SNYK-CC-K8S-42 + Public ID: SNYK-CC-K8S-42
  • Introduced through: - [DocId: 46] + [DocId: 47] spec @@ -789,7 +835,7 @@

    Container could be running with outdated image

  • - Line number: 16346 + Line number: 22203
@@ -806,7 +852,7 @@

Remediation

@@ -822,11 +868,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 42] + [DocId: 43] input @@ -847,7 +893,7 @@

    Container has no CPU limit

  • - Line number: 15809 + Line number: 21512
@@ -864,7 +910,7 @@

Remediation

@@ -880,11 +926,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 43] + [DocId: 44] input @@ -905,7 +951,7 @@

    Container has no CPU limit

  • - Line number: 15982 + Line number: 21763
@@ -922,7 +968,7 @@

Remediation

@@ -938,11 +984,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 43] + [DocId: 44] input @@ -963,7 +1009,7 @@

    Container has no CPU limit

  • - Line number: 15948 + Line number: 21729
@@ -980,7 +1026,7 @@

Remediation

@@ -996,11 +1042,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 44] + [DocId: 45] input @@ -1021,7 +1067,7 @@

    Container has no CPU limit

  • - Line number: 16038 + Line number: 21823
@@ -1038,7 +1084,7 @@

Remediation

@@ -1054,11 +1100,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 45] + [DocId: 46] input @@ -1079,7 +1125,7 @@

    Container has no CPU limit

  • - Line number: 16112 + Line number: 21922
@@ -1096,7 +1142,7 @@

Remediation

@@ -1112,11 +1158,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 46] + [DocId: 47] input @@ -1137,7 +1183,7 @@

    Container has no CPU limit

  • - Line number: 16346 + Line number: 22203
@@ -1154,7 +1200,7 @@

Remediation

@@ -1170,11 +1216,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 46] + [DocId: 47] input @@ -1195,7 +1241,7 @@

    Container has no CPU limit

  • - Line number: 16168 + Line number: 21979
@@ -1212,7 +1258,7 @@

Remediation

@@ -1228,11 +1274,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 47] + [DocId: 48] input @@ -1253,7 +1299,7 @@

    Container has no CPU limit

  • - Line number: 16431 + Line number: 22288
@@ -1270,7 +1316,7 @@

Remediation

@@ -1286,11 +1332,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 48] + [DocId: 49] input @@ -1311,7 +1357,7 @@

    Container has no CPU limit

  • - Line number: 16735 + Line number: 22634
@@ -1328,7 +1374,7 @@

Remediation

@@ -1344,11 +1390,11 @@

Container is running with multiple open ports

  • - Public ID: SNYK-CC-K8S-36 + Public ID: SNYK-CC-K8S-36
  • Introduced through: - [DocId: 43] + [DocId: 44] spec @@ -1363,7 +1409,7 @@

    Container is running with multiple open ports

  • - Line number: 15962 + Line number: 21743
@@ -1380,12 +1426,12 @@

Remediation

-

Container is running with writable root filesystem

+

Container is running without liveness probe

@@ -1396,13 +1442,11 @@

Container is running with writable root filesystem

  • - Public ID: SNYK-CC-K8S-8 + Public ID: SNYK-CC-K8S-41
  • Introduced through: - [DocId: 45] - - input + [DocId: 43] spec @@ -1410,33 +1454,31 @@

    Container is running with writable root filesystem

    spec - containers[redis] - - securityContext + containers[argocd-applicationset-controller] - readOnlyRootFilesystem + livenessProbe
  • - Line number: 16122 + Line number: 21512

Impact

-

Compromised process could abuse writable root filesystem to elevate privileges

+

Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

Remediation

-

Set `securityContext.readOnlyRootFilesystem` to `true`

+

Add `livenessProbe` attribute


@@ -1452,11 +1494,11 @@

Container is running without liveness probe

  • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
  • Introduced through: - [DocId: 42] + [DocId: 44] spec @@ -1464,14 +1506,14 @@

    Container is running without liveness probe

    spec - containers[argocd-applicationset-controller] + containers[dex] livenessProbe
  • - Line number: 15809 + Line number: 21729
@@ -1488,7 +1530,7 @@

Remediation

@@ -1504,11 +1546,11 @@

Container is running without liveness probe

  • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
  • Introduced through: - [DocId: 43] + [DocId: 46] spec @@ -1516,14 +1558,14 @@

    Container is running without liveness probe

    spec - containers[dex] + containers[redis] livenessProbe
  • - Line number: 15948 + Line number: 21922
@@ -1540,12 +1582,12 @@

Remediation

-

Container is running without liveness probe

+

Container is running without memory limit

@@ -1556,48 +1598,54 @@

Container is running without liveness probe

  • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
  • Introduced through: [DocId: 43] + input + spec template spec - initContainers[copyutil] + containers[argocd-applicationset-controller] - livenessProbe + resources + + limits + + memory
  • - Line number: 15982 + Line number: 21512

Impact

-

Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

+

Containers without memory limits are more likely to be terminated when the node runs out of memory

Remediation

-

Add `livenessProbe` attribute

+

Set `resources.limits.memory` value


-

Container is running without liveness probe

+

Container is running without memory limit

@@ -1608,11 +1656,13 @@

Container is running without liveness probe

  • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 45] + [DocId: 44] + + input spec @@ -1620,36 +1670,40 @@

    Container is running without liveness probe

    spec - containers[redis] + containers[dex] - livenessProbe + resources + + limits + + memory
  • - Line number: 16112 + Line number: 21729

Impact

-

Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

+

Containers without memory limits are more likely to be terminated when the node runs out of memory

Remediation

-

Add `livenessProbe` attribute

+

Set `resources.limits.memory` value


-

Container is running without liveness probe

+

Container is running without memory limit

@@ -1660,11 +1714,13 @@

Container is running without liveness probe

  • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 46] + [DocId: 44] + + input spec @@ -1674,29 +1730,33 @@

    Container is running without liveness probe

    initContainers[copyutil] - livenessProbe + resources + + limits + + memory
  • - Line number: 16346 + Line number: 21763

Impact

-

Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

+

Containers without memory limits are more likely to be terminated when the node runs out of memory

Remediation

-

Add `livenessProbe` attribute

+

Set `resources.limits.memory` value


@@ -1712,11 +1772,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 42] + [DocId: 45] input @@ -1726,7 +1786,7 @@

    Container is running without memory limit

    spec - containers[argocd-applicationset-controller] + containers[argocd-notifications-controller] resources @@ -1737,7 +1797,7 @@

    Container is running without memory limit

  • - Line number: 15809 + Line number: 21823
@@ -1754,7 +1814,7 @@

Remediation

@@ -1770,11 +1830,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 43] + [DocId: 46] input @@ -1784,7 +1844,7 @@

    Container is running without memory limit

    spec - containers[dex] + containers[redis] resources @@ -1795,7 +1855,7 @@

    Container is running without memory limit

  • - Line number: 15948 + Line number: 21922
@@ -1812,7 +1872,7 @@

Remediation

@@ -1828,11 +1888,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 43] + [DocId: 47] input @@ -1853,7 +1913,7 @@

    Container is running without memory limit

  • - Line number: 15982 + Line number: 22203
@@ -1870,7 +1930,7 @@

Remediation

@@ -1886,11 +1946,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 44] + [DocId: 47] input @@ -1900,7 +1960,7 @@

    Container is running without memory limit

    spec - containers[argocd-notifications-controller] + containers[argocd-repo-server] resources @@ -1911,7 +1971,7 @@

    Container is running without memory limit

  • - Line number: 16038 + Line number: 21979
@@ -1928,7 +1988,7 @@

Remediation

@@ -1944,11 +2004,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 45] + [DocId: 48] input @@ -1958,7 +2018,7 @@

    Container is running without memory limit

    spec - containers[redis] + containers[argocd-server] resources @@ -1969,7 +2029,7 @@

    Container is running without memory limit

  • - Line number: 16112 + Line number: 22288
@@ -1986,7 +2046,7 @@

Remediation

@@ -2002,11 +2062,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 46] + [DocId: 49] input @@ -2016,7 +2076,7 @@

    Container is running without memory limit

    spec - initContainers[copyutil] + containers[argocd-application-controller] resources @@ -2027,7 +2087,7 @@

    Container is running without memory limit

  • - Line number: 16346 + Line number: 22634
@@ -2044,12 +2104,12 @@

Remediation

-

Container is running without memory limit

+

Container's or Pod's UID could clash with host's UID

@@ -2060,11 +2120,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
  • Introduced through: - [DocId: 46] + [DocId: 43] input @@ -2074,40 +2134,94 @@

    Container is running without memory limit

    spec - containers[argocd-repo-server] + containers[argocd-applicationset-controller] - resources + securityContext - limits + runAsUser + +
  • + +
  • + Line number: 21653 +
  • +
+ +
+ +

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] - memory + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser
  • - Line number: 16168 + Line number: 21771

Impact

-

Containers without memory limits are more likely to be terminated when the node runs out of memory

+

UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

Remediation

-

Set `resources.limits.memory` value

+

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 is running without memory limit

+

Container's or Pod's UID could clash with host's UID

@@ -2118,7 +2232,175 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11 +
  • + +
  • Introduced through: + [DocId: 44] + + input + + spec + + template + + spec + + containers[dex] + + securityContext + + runAsUser + +
  • + +
  • + Line number: 21746 +
  • +
+ +
+ +

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-notifications-controller] + + securityContext + + runAsUser + +
  • + +
  • + Line number: 21856 +
  • +
+ +
+ +

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[redis] + + securityContext + + runAsUser + +
  • + +
  • + Line number: 21932 +
  • +
+ +
+ +

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: @@ -2132,40 +2414,94 @@

    Container is running without memory limit

    spec - containers[argocd-server] + initContainers[copyutil] - resources + securityContext - limits + runAsUser + +
  • + +
  • + Line number: 22210 +
  • +
+ +
+ +

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] - memory + input + + spec + + template + + spec + + containers[argocd-repo-server] + + securityContext + + runAsUser
  • - Line number: 16431 + Line number: 22176

Impact

-

Containers without memory limits are more likely to be terminated when the node runs out of memory

+

UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

Remediation

-

Set `resources.limits.memory` value

+

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 is running without memory limit

+

Container's or Pod's UID could clash with host's UID

@@ -2176,7 +2512,7 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
  • Introduced through: @@ -2190,35 +2526,89 @@

    Container is running without memory limit

    spec - containers[argocd-application-controller] + containers[argocd-server] - resources + securityContext - limits + runAsUser + +
  • + +
  • + Line number: 22544 +
  • +
+ +
+ +

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: 49] - memory + input + + spec + + template + + spec + + containers[argocd-application-controller] + + securityContext + + runAsUser
  • - Line number: 16735 + Line number: 22824

Impact

-

Containers without memory limits are more likely to be terminated when the node runs out of memory

+

UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

Remediation

-

Set `resources.limits.memory` value

+

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/master/argocd-iac-namespace-install.html b/docs/snyk/master/argocd-iac-namespace-install.html index 76128f58b2dd9..1795ba67af3c6 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

-

January 22nd 2023, 12:17:30 am

+

March 24th 2024, 12:17:26 am (UTC+00:00)

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

Snyk test report

-
32 total issues
+
38 total issues
@@ -483,7 +483,7 @@

Snyk test report

-

Role with dangerous permissions

+

Role or ClusterRole with dangerous permissions

@@ -494,7 +494,7 @@

Role with dangerous permissions

  • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
  • Introduced through: @@ -514,22 +514,22 @@

    Role with dangerous permissions


    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


-

Role with dangerous permissions

+

Role or ClusterRole with dangerous permissions

@@ -540,7 +540,7 @@

Role with dangerous permissions

  • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
  • Introduced through: @@ -553,29 +553,29 @@

    Role with dangerous permissions

  • - Line number: 154 + Line number: 162

Impact

-

Using this role grants dangerous permissions

+

Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

Remediation

-

Consider removing this permissions

+

Consider removing these permissions


-

Role with dangerous permissions

+

Role or ClusterRole with dangerous permissions

@@ -586,7 +586,7 @@

Role with dangerous permissions

  • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
  • Introduced through: @@ -599,29 +599,29 @@

    Role with dangerous permissions

  • - Line number: 182 + Line number: 190

Impact

-

Using this role grants dangerous permissions

+

Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

Remediation

-

Consider removing this permissions

+

Consider removing these permissions


-

Role with dangerous permissions

+

Role or ClusterRole with dangerous permissions

@@ -632,42 +632,42 @@

Role with dangerous permissions

  • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
  • Introduced through: [DocId: 10] - rules[3] + rules[1] resources
  • - Line number: 226 + Line number: 220

Impact

-

Using this role grants dangerous permissions

+

Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

Remediation

-

Consider removing this permissions

+

Consider removing these permissions


-

Role with dangerous permissions

+

Role or ClusterRole with dangerous permissions

@@ -678,42 +678,42 @@

Role with dangerous permissions

  • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
  • Introduced through: [DocId: 10] - rules[1] + rules[3] resources
  • - Line number: 208 + Line number: 238

Impact

-

Using this role grants dangerous permissions

+

Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

Remediation

-

Consider removing this permissions

+

Consider removing these permissions


-

Role with dangerous permissions

+

Role or ClusterRole with dangerous permissions

@@ -724,7 +724,7 @@

Role with dangerous permissions

  • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
  • Introduced through: @@ -737,24 +737,24 @@

    Role with dangerous permissions

  • - Line number: 242 + Line number: 254

Impact

-

Using this role grants dangerous permissions

+

Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

Remediation

-

Consider removing this permissions

+

Consider removing these permissions


@@ -770,11 +770,11 @@

Container could be running with outdated image

  • - Public ID: SNYK-CC-K8S-42 + Public ID: SNYK-CC-K8S-42
  • Introduced through: - [DocId: 39] + [DocId: 38] spec @@ -789,7 +789,7 @@

    Container could be running with outdated image

  • - Line number: 1153 + Line number: 1324
@@ -806,7 +806,7 @@

Remediation

@@ -822,11 +822,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 35] + [DocId: 34] input @@ -847,7 +847,7 @@

    Container has no CPU limit

  • - Line number: 616 + Line number: 633
@@ -864,7 +864,7 @@

Remediation

@@ -880,11 +880,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 36] + [DocId: 35] input @@ -905,7 +905,7 @@

    Container has no CPU limit

  • - Line number: 789 + Line number: 884
@@ -922,7 +922,7 @@

Remediation

@@ -938,11 +938,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 36] + [DocId: 35] input @@ -963,7 +963,7 @@

    Container has no CPU limit

  • - Line number: 755 + Line number: 850
@@ -980,7 +980,7 @@

Remediation

@@ -996,11 +996,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 37] + [DocId: 36] input @@ -1021,7 +1021,7 @@

    Container has no CPU limit

  • - Line number: 845 + Line number: 944
@@ -1038,7 +1038,7 @@

Remediation

@@ -1054,11 +1054,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 38] + [DocId: 37] input @@ -1079,7 +1079,7 @@

    Container has no CPU limit

  • - Line number: 919 + Line number: 1043
@@ -1096,7 +1096,7 @@

Remediation

@@ -1112,11 +1112,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 39] + [DocId: 38] input @@ -1137,7 +1137,7 @@

    Container has no CPU limit

  • - Line number: 1153 + Line number: 1324
@@ -1154,7 +1154,7 @@

Remediation

@@ -1170,11 +1170,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 39] + [DocId: 38] input @@ -1195,7 +1195,7 @@

    Container has no CPU limit

  • - Line number: 975 + Line number: 1100
@@ -1212,7 +1212,7 @@

Remediation

@@ -1228,11 +1228,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 40] + [DocId: 39] input @@ -1253,7 +1253,7 @@

    Container has no CPU limit

  • - Line number: 1238 + Line number: 1409
@@ -1270,7 +1270,7 @@

Remediation

@@ -1286,11 +1286,11 @@

Container has no CPU limit

  • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
  • Introduced through: - [DocId: 41] + [DocId: 40] input @@ -1311,7 +1311,7 @@

    Container has no CPU limit

  • - Line number: 1542 + Line number: 1755
@@ -1328,7 +1328,7 @@

Remediation

@@ -1344,11 +1344,11 @@

Container is running with multiple open ports

  • - Public ID: SNYK-CC-K8S-36 + Public ID: SNYK-CC-K8S-36
  • Introduced through: - [DocId: 36] + [DocId: 35] spec @@ -1363,7 +1363,7 @@

    Container is running with multiple open ports

  • - Line number: 769 + Line number: 864
@@ -1380,12 +1380,12 @@

Remediation

-

Container is running with writable root filesystem

+

Container is running without liveness probe

@@ -1396,13 +1396,11 @@

Container is running with writable root filesystem

  • - Public ID: SNYK-CC-K8S-8 + Public ID: SNYK-CC-K8S-41
  • Introduced through: - [DocId: 38] - - input + [DocId: 34] spec @@ -1410,33 +1408,31 @@

    Container is running with writable root filesystem

    spec - containers[redis] - - securityContext + containers[argocd-applicationset-controller] - readOnlyRootFilesystem + livenessProbe
  • - Line number: 929 + Line number: 633

Impact

-

Compromised process could abuse writable root filesystem to elevate privileges

+

Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

Remediation

-

Set `securityContext.readOnlyRootFilesystem` to `true`

+

Add `livenessProbe` attribute


@@ -1452,7 +1448,7 @@

Container is running without liveness probe

  • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
  • Introduced through: @@ -1464,14 +1460,14 @@

    Container is running without liveness probe

    spec - containers[argocd-applicationset-controller] + containers[dex] livenessProbe
  • - Line number: 616 + Line number: 850
@@ -1488,7 +1484,7 @@

Remediation

@@ -1504,11 +1500,11 @@

Container is running without liveness probe

  • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
  • Introduced through: - [DocId: 36] + [DocId: 37] spec @@ -1516,14 +1512,14 @@

    Container is running without liveness probe

    spec - containers[dex] + containers[redis] livenessProbe
  • - Line number: 755 + Line number: 1043
@@ -1540,12 +1536,12 @@

Remediation

-

Container is running without liveness probe

+

Container is running without memory limit

@@ -1556,11 +1552,13 @@

Container is running without liveness probe

  • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 36] + [DocId: 34] + + input spec @@ -1568,36 +1566,40 @@

    Container is running without liveness probe

    spec - initContainers[copyutil] + containers[argocd-applicationset-controller] - livenessProbe + resources + + limits + + memory
  • - Line number: 789 + Line number: 633

Impact

-

Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

+

Containers without memory limits are more likely to be terminated when the node runs out of memory

Remediation

-

Add `livenessProbe` attribute

+

Set `resources.limits.memory` value


-

Container is running without liveness probe

+

Container is running without memory limit

@@ -1608,11 +1610,13 @@

Container is running without liveness probe

  • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 38] + [DocId: 35] + + input spec @@ -1620,36 +1624,40 @@

    Container is running without liveness probe

    spec - containers[redis] + containers[dex] - livenessProbe + resources + + limits + + memory
  • - Line number: 919 + Line number: 850

Impact

-

Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

+

Containers without memory limits are more likely to be terminated when the node runs out of memory

Remediation

-

Add `livenessProbe` attribute

+

Set `resources.limits.memory` value


-

Container is running without liveness probe

+

Container is running without memory limit

@@ -1660,11 +1668,13 @@

Container is running without liveness probe

  • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 39] + [DocId: 35] + + input spec @@ -1674,29 +1684,33 @@

    Container is running without liveness probe

    initContainers[copyutil] - livenessProbe + resources + + limits + + memory
  • - Line number: 1153 + Line number: 884

Impact

-

Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

+

Containers without memory limits are more likely to be terminated when the node runs out of memory

Remediation

-

Add `livenessProbe` attribute

+

Set `resources.limits.memory` value


@@ -1712,11 +1726,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 35] + [DocId: 36] input @@ -1726,7 +1740,7 @@

    Container is running without memory limit

    spec - containers[argocd-applicationset-controller] + containers[argocd-notifications-controller] resources @@ -1737,7 +1751,7 @@

    Container is running without memory limit

  • - Line number: 616 + Line number: 944
@@ -1754,7 +1768,7 @@

Remediation

@@ -1770,11 +1784,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 36] + [DocId: 37] input @@ -1784,7 +1798,7 @@

    Container is running without memory limit

    spec - containers[dex] + containers[redis] resources @@ -1795,7 +1809,7 @@

    Container is running without memory limit

  • - Line number: 755 + Line number: 1043
@@ -1812,7 +1826,7 @@

Remediation

@@ -1828,11 +1842,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 36] + [DocId: 38] input @@ -1853,7 +1867,7 @@

    Container is running without memory limit

  • - Line number: 789 + Line number: 1324
@@ -1870,7 +1884,7 @@

Remediation

@@ -1886,11 +1900,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 37] + [DocId: 38] input @@ -1900,7 +1914,7 @@

    Container is running without memory limit

    spec - containers[argocd-notifications-controller] + containers[argocd-repo-server] resources @@ -1911,7 +1925,7 @@

    Container is running without memory limit

  • - Line number: 845 + Line number: 1100
@@ -1928,7 +1942,7 @@

Remediation

@@ -1944,11 +1958,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 38] + [DocId: 39] input @@ -1958,7 +1972,7 @@

    Container is running without memory limit

    spec - containers[redis] + containers[argocd-server] resources @@ -1969,7 +1983,7 @@

    Container is running without memory limit

  • - Line number: 919 + Line number: 1409
@@ -1986,7 +2000,7 @@

Remediation

@@ -2002,11 +2016,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
  • Introduced through: - [DocId: 39] + [DocId: 40] input @@ -2016,7 +2030,7 @@

    Container is running without memory limit

    spec - initContainers[copyutil] + containers[argocd-application-controller] resources @@ -2027,7 +2041,7 @@

    Container is running without memory limit

  • - Line number: 1153 + Line number: 1755
@@ -2044,12 +2058,12 @@

Remediation

-

Container is running without memory limit

+

Container's or Pod's UID could clash with host's UID

@@ -2060,11 +2074,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
  • Introduced through: - [DocId: 39] + [DocId: 34] input @@ -2074,40 +2088,94 @@

    Container is running without memory limit

    spec - containers[argocd-repo-server] + containers[argocd-applicationset-controller] - resources + securityContext - limits + runAsUser + +
  • + +
  • + Line number: 774 +
  • +
+ +
+ +

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] - memory + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser
  • - Line number: 975 + Line number: 892

Impact

-

Containers without memory limits are more likely to be terminated when the node runs out of memory

+

UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

Remediation

-

Set `resources.limits.memory` value

+

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 is running without memory limit

+

Container's or Pod's UID could clash with host's UID

@@ -2118,11 +2186,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
  • Introduced through: - [DocId: 40] + [DocId: 35] input @@ -2132,40 +2200,94 @@

    Container is running without memory limit

    spec - containers[argocd-server] + containers[dex] - resources + securityContext - limits + runAsUser + +
  • + +
  • + Line number: 867 +
  • +
+ +
+ +

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] - memory + input + + spec + + template + + spec + + containers[argocd-notifications-controller] + + securityContext + + runAsUser
  • - Line number: 1238 + Line number: 977

Impact

-

Containers without memory limits are more likely to be terminated when the node runs out of memory

+

UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

Remediation

-

Set `resources.limits.memory` value

+

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 is running without memory limit

+

Container's or Pod's UID could clash with host's UID

@@ -2176,11 +2298,11 @@

Container is running without memory limit

  • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
  • Introduced through: - [DocId: 41] + [DocId: 37] input @@ -2190,35 +2312,257 @@

    Container is running without memory limit

    spec - containers[argocd-application-controller] + containers[redis] - resources + securityContext - limits + runAsUser + +
  • + +
  • + Line number: 1053 +
  • +
+ +
+ +

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] - memory + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser
  • - Line number: 1542 + Line number: 1331

Impact

-

Containers without memory limits are more likely to be terminated when the node runs out of memory

+

UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

Remediation

-

Set `resources.limits.memory` value

+

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: 1297 +
  • +
+ +
+ +

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: 1665 +
  • +
+ +
+ +

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: 1945 +
  • +
+ +
+ +

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/master/argocd-test.html b/docs/snyk/master/argocd-test.html index a139b2f3831bd..b745cf7cbd119 100644 --- a/docs/snyk/master/argocd-test.html +++ b/docs/snyk/master/argocd-test.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,19 +456,20 @@

Snyk test report

-

January 22nd 2023, 12:15:25 am

+

March 24th 2024, 12:15:25 am (UTC+00:00)

Scanned the following paths:
    -
  • /argo-cd/argoproj/argo-cd/v2 (gomodules)
  • /argo-cd (yarn)
  • +
  • /argo-cd/argoproj/argo-cd/v2/go.mod (gomodules)
  • +
  • /argo-cd/ui/yarn.lock (yarn)
-
1 known vulnerabilities
-
1 vulnerable dependency paths
-
1728 dependencies
+
9 known vulnerabilities
+
144 vulnerable dependency paths
+
2037 dependencies
@@ -477,7 +478,7 @@

Snyk test report

-

Regular Expression Denial of Service (ReDoS)

+

LGPL-3.0 license

@@ -488,18 +489,3041 @@

Regular Expression Denial of Service (ReDoS)

  • - Package Manager: npm + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
  • +
  • + 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

+ +
+ + + +
+
+

Infinite loop

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
  • +
  • + Package Manager: golang
  • Vulnerable module: - cookiejar + google.golang.org/protobuf/internal/encoding/json +
  • + +
  • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 and others +
  • +
+ +
+ + +

Detailed paths

+ +
    +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/pkg/grpc/http@#d56162821bd1 + + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.21.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health/grpc_health_v1@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.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.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.59.0 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.59.0 + + google.golang.org/grpc/health/grpc_health_v1@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 + + + +
  • +
+ +
+ +
+ +

Overview

+

Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

+

Note:

+

This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

+

Remediation

+

Upgrade google.golang.org/protobuf/internal/encoding/json to version 1.33.0 or higher.

+

References

+ + +
+ + + +
+
+

Stack-based Buffer Overflow

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
  • +
  • + Package Manager: golang +
  • +
  • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
  • + +
  • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 and others +
  • +
+ +
+ + +

Detailed paths

+ +
    +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.21.0 + + go.opentelemetry.io/proto/otlp/collector/trace/v1@1.0.0 + + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.16.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/pkg/grpc/http@#d56162821bd1 + + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2/apierror@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.21.0 + + go.opentelemetry.io/proto/otlp/collector/trace/v1@1.0.0 + + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.16.0 + + google.golang.org/protobuf/types/known/structpb@1.31.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.21.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health/grpc_health_v1@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2/apierror@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2/apierror@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.21.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health/grpc_health_v1@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.59.0 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.59.0 + + google.golang.org/grpc/health/grpc_health_v1@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2/apierror@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2/apierror@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.59.0 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.59.0 + + google.golang.org/grpc/health/grpc_health_v1@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
+ +
+ +
+ +

Overview

+

Affected versions of this package are vulnerable to Stack-based Buffer Overflow when processing input that uses pathologically deep nesting.

+

Remediation

+

Upgrade google.golang.org/protobuf/encoding/protojson to version 1.32.0 or higher.

+

References

+ + +
+ + + +
+
+

Infinite loop

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
  • +
  • + Package Manager: golang +
  • +
  • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
  • + +
  • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 and others +
  • +
+ +
+ + +

Detailed paths

+ +
    +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.21.0 + + go.opentelemetry.io/proto/otlp/collector/trace/v1@1.0.0 + + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.16.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/pkg/grpc/http@#d56162821bd1 + + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2/apierror@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.21.0 + + go.opentelemetry.io/proto/otlp/collector/trace/v1@1.0.0 + + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.16.0 + + google.golang.org/protobuf/types/known/structpb@1.31.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.21.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health/grpc_health_v1@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2/apierror@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2/apierror@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.21.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health/grpc_health_v1@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.59.0 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.59.0 + + google.golang.org/grpc/health/grpc_health_v1@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2/apierror@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2/apierror@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/internal/gensupport@0.132.0 + + github.com/googleapis/gax-go/v2@2.12.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.59.0 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.59.0 + + google.golang.org/grpc/health/grpc_health_v1@1.59.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.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.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + google.golang.org/api/chat/v1@0.132.0 + + google.golang.org/api/transport/http@0.132.0 + + google.golang.org/api/option@0.132.0 + + google.golang.org/grpc@1.59.0 + + google.golang.org/grpc/internal/transport@1.59.0 + + google.golang.org/grpc/internal/pretty@1.59.0 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + + +
  • +
+ +
+ +
+ +

Overview

+

Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

+

Note:

+

This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

+

Remediation

+

Upgrade google.golang.org/protobuf/encoding/protojson to version 1.33.0 or higher.

+

References

+ + +
+ + + +
+
+

MPL-2.0 license

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
  • +
  • + 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/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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@#2daee6022f41 + + 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@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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 +
+ +
+ +
    +
  • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
  • +
  • + Package Manager: golang +
  • +
  • + Module: + + github.com/hashicorp/go-cleanhttp
  • Introduced through: - argo-cd-ui@1.0.0, superagent@7.1.6 and others + github.com/argoproj/argo-cd/v2@0.0.0, github.com/hashicorp/go-retryablehttp@0.7.4 and others
@@ -511,11 +3535,122 @@

Detailed paths

  • Introduced through: - argo-cd-ui@1.0.0 + 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@#2daee6022f41 + + 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@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 + + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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@#2daee6022f41 - superagent@7.1.6 + github.com/argoproj/notifications-engine/pkg/subscriptions@#2daee6022f41 - cookiejar@2.1.3 + github.com/argoproj/notifications-engine/pkg/services@#2daee6022f41 + + 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 @@ -526,92 +3661,72 @@

    Detailed paths


    -

    Overview

    -

    Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) via the Cookie.parse function, which uses an insecure regular expression.

    -

    PoC

    -
    const { CookieJar } = require("cookiejar");
    -        
    -        const jar = new CookieJar();
    -        
    -        const start = performance.now();
    -        const attack = "a" + "t".repeat(50_000);
    -        jar.setCookie(attack);
    -        console.log(`CookieJar.setCookie(): ${performance.now() - start}`);
    -        
    -

    Details

    -

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.

    -

    The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.

    -

    Let’s take the following regular expression as an example:

    -
    regex = /A(B|C+)+D/
    -        
    -

    This regular expression accomplishes the following:

    -
      -
    • A The string must start with the letter 'A'
    • -
    • (B|C+)+ The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the + matches one or more times). The + at the end of this section states that we can look for one or more matches of this section.
    • -
    • D Finally, we ensure this section of the string ends with a 'D'
    • -
    -

    The expression would match inputs such as ABBD, ABCCCCD, ABCBCCCD and ACCCCCD

    -

    It most cases, it doesn't take very long for a regex engine to find a match:

    -
    $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
    -        0.04s user 0.01s system 95% cpu 0.052 total
    -        
    -        $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
    -        1.79s user 0.02s system 99% cpu 1.812 total
    -        
    -

    The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.

    -

    Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.

    -

    Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:

    -
      -
    1. CCC
    2. -
    3. CC+C
    4. -
    5. C+CC
    6. -
    7. C+C+C.
    8. -
    -

    The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.

    -

    From there, the number of steps the engine must use to validate a string just continues to grow.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StringNumber of C'sNumber of steps
    ACCCX338
    ACCCCX471
    ACCCCCX5136
    ACCCCCCCCCCCCCCX1465,553
    -

    By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.

    -

    Remediation

    -

    Upgrade cookiejar to version 2.1.4 or higher.

    -

    References

    - +

    MPL-2.0 license

    + +
    + + + +
+
+

MPL-2.0 license

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
  • +
  • + 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/master/ghcr.io_dexidp_dex_v2.35.3.html b/docs/snyk/master/ghcr.io_dexidp_dex_v2.35.3.html deleted file mode 100644 index cc34f61f14aba..0000000000000 --- a/docs/snyk/master/ghcr.io_dexidp_dex_v2.35.3.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
-
-
-
- - - Snyk - Open Source Security - - - - - - - -
-

Snyk test report

- -

January 22nd 2023, 12:15:32 am

-
-
- Scanned the following path: -
    -
  • ghcr.io/dexidp/dex:v2.35.3/dexidp/dex (apk)
  • -
-
- -
-
0 known vulnerabilities
-
0 vulnerable dependency paths
-
14 dependencies
-
-
-
-
-
- - - - - - - -
Project docker-image|ghcr.io/dexidp/dex
Path ghcr.io/dexidp/dex:v2.35.3/dexidp/dex
Package Manager apk
-
-
- No known vulnerabilities detected. -
-
- - - diff --git a/docs/snyk/master/ghcr.io_dexidp_dex_v2.38.0.html b/docs/snyk/master/ghcr.io_dexidp_dex_v2.38.0.html new file mode 100644 index 0000000000000..7d85ddf3861f8 --- /dev/null +++ b/docs/snyk/master/ghcr.io_dexidp_dex_v2.38.0.html @@ -0,0 +1,2561 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
+
+
+
+ + + Snyk - Open Source Security + + + + + + + +
+

Snyk test report

+ +

March 24th 2024, 12:15:32 am (UTC+00:00)

+
+
+ Scanned the following paths: +
    +
  • ghcr.io/dexidp/dex:v2.38.0/dexidp/dex (apk)
  • +
  • ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3//usr/local/bin/gomplate (gomodules)
  • +
  • ghcr.io/dexidp/dex:v2.38.0/dexidp/dex//usr/local/bin/docker-entrypoint (gomodules)
  • +
  • ghcr.io/dexidp/dex:v2.38.0/dexidp/dex//usr/local/bin/dex (gomodules)
  • +
+
+ +
+
27 known vulnerabilities
+
62 vulnerable dependency paths
+
829 dependencies
+
+
+
+
+ +
+
+
+

Out-of-bounds Write

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Package Manager: alpine:3.19 +
  • +
  • + Vulnerable module: + + openssl/libcrypto3 +
  • + +
  • Introduced through: + + docker-image|ghcr.io/dexidp/dex@v2.38.0 and openssl/libcrypto3@3.1.4-r2 + +
  • +
+ +
+ + +

Detailed paths

+ +
    +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + openssl/libcrypto3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libcrypto3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + busybox/ssl_client@1.36.1-r15 + + openssl/libcrypto3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libssl3@3.1.4-r2 + + openssl/libcrypto3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + openssl/libssl3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libssl3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + busybox/ssl_client@1.36.1-r15 + + openssl/libssl3@3.1.4-r2 + + + +
  • +
+ +
+ +
+ +

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.19 relevant fixed versions and status.

+

Issue summary: The POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

+

Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

+

The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

+

The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

+

The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

+

Remediation

+

Upgrade Alpine:3.19 openssl to version 3.1.4-r3 or higher.

+

References

+ + +
+ + + +
+
+

CVE-2024-0727

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Package Manager: alpine:3.19 +
  • +
  • + Vulnerable module: + + openssl/libcrypto3 +
  • + +
  • Introduced through: + + docker-image|ghcr.io/dexidp/dex@v2.38.0 and openssl/libcrypto3@3.1.4-r2 + +
  • +
+ +
+ + +

Detailed paths

+ +
    +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + openssl/libcrypto3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libcrypto3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + busybox/ssl_client@1.36.1-r15 + + openssl/libcrypto3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libssl3@3.1.4-r2 + + openssl/libcrypto3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + openssl/libssl3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libssl3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + busybox/ssl_client@1.36.1-r15 + + openssl/libssl3@3.1.4-r2 + + + +
  • +
+ +
+ +
+ +

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.19 relevant fixed versions and status.

+

Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

+

Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

+

A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

+

OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

+

We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

+

The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

+

Remediation

+

Upgrade Alpine:3.19 openssl to version 3.1.4-r5 or higher.

+

References

+ + +
+ + + +
+
+

Infinite loop

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + Package Manager: golang +
  • +
  • + Vulnerable module: + + google.golang.org/protobuf/internal/encoding/json +
  • + +
  • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/protobuf/internal/encoding/json@v1.31.0 + +
  • +
+ +
+ + +

Detailed paths

+ +
    +
  • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/protobuf/internal/encoding/json@v1.31.0 + + + +
  • +
  • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/protobuf/internal/encoding/json@v1.32.0 + + + +
  • +
+ +
+ +
+ +

Overview

+

Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

+

Note:

+

This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

+

Remediation

+

Upgrade google.golang.org/protobuf/internal/encoding/json to version 1.33.0 or higher.

+

References

+ + +
+ + + +
+
+

Stack-based Buffer Overflow

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + Package Manager: golang +
  • +
  • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
  • + +
  • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/protobuf/encoding/protojson@v1.31.0 + +
  • +
+ +
+ + +

Detailed paths

+ +
    +
  • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
  • +
+ +
+ +
+ +

Overview

+

Affected versions of this package are vulnerable to Stack-based Buffer Overflow when processing input that uses pathologically deep nesting.

+

Remediation

+

Upgrade google.golang.org/protobuf/encoding/protojson to version 1.32.0 or higher.

+

References

+ + +
+ + + +
+
+

Infinite loop

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + Package Manager: golang +
  • +
  • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
  • + +
  • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/protobuf/encoding/protojson@v1.31.0 + +
  • +
+ +
+ + +

Detailed paths

+ +
    +
  • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
  • +
  • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/protobuf/encoding/protojson@v1.32.0 + + + +
  • +
+ +
+ +
+ +

Overview

+

Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

+

Note:

+

This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

+

Remediation

+

Upgrade google.golang.org/protobuf/encoding/protojson to version 1.33.0 or higher.

+

References

+ + +
+ + + +
+
+

MPL-2.0 license

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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/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 + + + +
  • +
+ +
+ +
+ +

MPL-2.0 license

+ +
+ + + +
+
+

MPL-2.0 license

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/dexidp/dex /usr/local/bin/dex +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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/token@v1.0.0 + + + +
  • +
+ +
+ +
+ +

MPL-2.0 license

+ +
+ + + +
+
+

MPL-2.0 license

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
  • +
  • + 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 +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/dexidp/dex /usr/local/bin/dex +
  • +
  • + 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

+ +
+ + + +
+
+

Improper Handling of Highly Compressed Data (Data Amplification)

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: ghcr.io/dexidp/dex:v2.38.0/dexidp/dex /usr/local/bin/dex +
  • +
  • + Package Manager: golang +
  • +
  • + Vulnerable module: + + github.com/go-jose/go-jose/v3 +
  • + +
  • Introduced through: + + github.com/dexidp/dex@* and github.com/go-jose/go-jose/v3@v3.0.1 + +
  • +
+ +
+ + +

Detailed paths

+ +
    +
  • + Introduced through: + github.com/dexidp/dex@* + + github.com/go-jose/go-jose/v3@v3.0.1 + + + +
  • +
+ +
+ +
+ +

Overview

+

Affected versions of this package are vulnerable to Improper Handling of Highly Compressed Data (Data Amplification). An attacker could send a JWE containing compressed data that, when decompressed by Decrypt or DecryptMulti, would use large amounts of memory and CPU.

+

Remediation

+

Upgrade github.com/go-jose/go-jose/v3 to version 3.0.3 or higher.

+

References

+ + +
+ + + +
+
+

CVE-2023-6237

+
+ +
+ low severity +
+ +
+ +
    +
  • + Package Manager: alpine:3.19 +
  • +
  • + Vulnerable module: + + openssl/libcrypto3 +
  • + +
  • Introduced through: + + docker-image|ghcr.io/dexidp/dex@v2.38.0 and openssl/libcrypto3@3.1.4-r2 + +
  • +
+ +
+ + +

Detailed paths

+ +
    +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + openssl/libcrypto3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libcrypto3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + busybox/ssl_client@1.36.1-r15 + + openssl/libcrypto3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libssl3@3.1.4-r2 + + openssl/libcrypto3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + openssl/libssl3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libssl3@3.1.4-r2 + + + +
  • +
  • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.38.0 + + busybox/ssl_client@1.36.1-r15 + + openssl/libssl3@3.1.4-r2 + + + +
  • +
+ +
+ +
+ +

NVD Description

+

This vulnerability has not been analyzed by NVD yet.

+

Remediation

+

Upgrade Alpine:3.19 openssl to version 3.1.4-r4 or higher.

+ +
+ + + +
+
+
+
+ + + diff --git a/docs/snyk/master/haproxy_2.6.14-alpine.html b/docs/snyk/master/haproxy_2.6.14-alpine.html new file mode 100644 index 0000000000000..106ec7c2cc72f --- /dev/null +++ b/docs/snyk/master/haproxy_2.6.14-alpine.html @@ -0,0 +1,1376 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
+
+
+
+ + + Snyk - Open Source Security + + + + + + + +
+

Snyk test report

+ +

March 24th 2024, 12:15:37 am (UTC+00:00)

+
+
+ Scanned the following path: +
    +
  • haproxy:2.6.14-alpine (apk)
  • +
+
+ +
+
5 known vulnerabilities
+
45 vulnerable dependency paths
+
18 dependencies
+
+
+
+
+
+ + + + + + + +
Project docker-image|haproxy
Path haproxy:2.6.14-alpine
Package Manager apk
+
+
+
+
+

CVE-2023-5363

+
+ +
+ high 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

+ + +
+ + + +
+
+

Improper Check for Unusual or Exceptional Conditions

+
+ +
+ medium 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: Generating excessively long X9.42 DH keys or checking + excessively long X9.42 DH keys or parameters may be very slow.

+

Impact summary: Applications that use the functions DH_generate_key() to + generate an X9.42 DH key may experience long delays. Likewise, applications + that use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check() + to check an X9.42 DH key or X9.42 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.

+

While DH_check() performs all the necessary checks (as of CVE-2023-3817), + DH_check_pub_key() doesn't make any of these checks, and is therefore + vulnerable for excessively large P and Q parameters.

+

Likewise, while DH_generate_key() performs a check for an excessively large + P, it doesn't check for an excessively large Q.

+

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

+

DH_generate_key() and DH_check_pub_key() are also 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_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().

+

Also vulnerable are the OpenSSL pkey command line application when using the + "-pubcheck" option, as well as the OpenSSL genpkey command line application.

+

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.4-r1 or higher.

+

References

+ + +
+ + + +
+
+

Out-of-bounds Write

+
+ +
+ medium 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: The POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

+

Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

+

The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

+

The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

+

The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

+

Remediation

+

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

+

References

+ + +
+ + + +
+
+

CVE-2024-0727

+
+ +
+ medium 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: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

+

Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

+

A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

+

OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

+

We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

+

The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

+

Remediation

+

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

+

References

+ + +
+ + + +
+
+

CVE-2023-6237

+
+ +
+ 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

+

This vulnerability has not been analyzed by NVD yet.

+

Remediation

+

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

+ +
+ + + +
+
+
+
+ + + diff --git a/docs/snyk/master/haproxy_2.6.2-alpine.html b/docs/snyk/master/haproxy_2.6.2-alpine.html deleted file mode 100644 index c484716686348..0000000000000 --- a/docs/snyk/master/haproxy_2.6.2-alpine.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
-
-
-
- - - Snyk - Open Source Security - - - - - - - -
-

Snyk test report

- -

January 22nd 2023, 12:15:36 am

-
-
- Scanned the following path: -
    -
  • haproxy:2.6.2-alpine (apk)
  • -
-
- -
-
0 known vulnerabilities
-
0 vulnerable dependency paths
-
17 dependencies
-
-
-
-
-
- - - - - - - -
Project docker-image|haproxy
Path haproxy:2.6.2-alpine
Package Manager apk
-
-
- No known vulnerabilities detected. -
-
- - - diff --git a/docs/snyk/master/quay.io_argoproj_argocd_latest.html b/docs/snyk/master/quay.io_argoproj_argocd_latest.html index e2ee32c460857..045db290b0fbb 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,37 +456,32 @@

Snyk test report

-

January 22nd 2023, 12:15:59 am

+

March 24th 2024, 12:15:54 am (UTC+00:00)

- Scanned the following path: + Scanned the following paths:
    -
  • quay.io/argoproj/argocd:latest/argoproj/argocd (deb)
  • +
  • quay.io/argoproj/argocd:latest/argoproj/argocd/Dockerfile (deb)
  • +
  • quay.io/argoproj/argocd:latest/argoproj/argo-cd/v2//usr/local/bin/argocd (gomodules)
  • +
  • quay.io/argoproj/argocd:latest//usr/local/bin/kustomize (gomodules)
  • +
  • quay.io/argoproj/argocd:latest/helm/v3//usr/local/bin/helm (gomodules)
  • +
  • quay.io/argoproj/argocd:latest/git-lfs/git-lfs//usr/bin/git-lfs (gomodules)
-
16 known vulnerabilities
-
102 vulnerable dependency paths
-
162 dependencies
+
32 known vulnerabilities
+
175 vulnerable dependency paths
+
2276 dependencies
-
- - - - - - - -
Project docker-image|quay.io/argoproj/argocd
Path quay.io/argoproj/argocd:latest/argoproj/argocd
Package Manager deb
Manifest Dockerfile
-
+
-

Off-by-one Error

+

CVE-2020-22916

@@ -496,18 +491,173 @@

Off-by-one Error


    +
  • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
  • Package Manager: ubuntu:22.04
  • Vulnerable module: - systemd/libsystemd0 + xz-utils/liblzma5 +
  • + +
  • Introduced through: + + docker-image|quay.io/argoproj/argocd@latest and xz-utils/liblzma5@5.2.5-2ubuntu1 + +
  • +
+ +
+ + +

Detailed paths

+ +
    +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + 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.

+

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

+ + +
+ + + +
+
+

CVE-2023-51767

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
  • +
  • + Package Manager: ubuntu:22.04 +
  • +
  • + Vulnerable module: + + openssh/openssh-client +
  • + +
  • Introduced through: + + docker-image|quay.io/argoproj/argocd@latest and openssh/openssh-client@1:8.9p1-3ubuntu0.6 + +
  • +
+ +
+ + +

Detailed paths

+ +
    +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + + +
  • +
+ +
+ +
+ +

NVD Description

+

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

+

OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.

+

Remediation

+

There is no fixed version for Ubuntu:22.04 openssh.

+

References

+ + +
+ + + +
+
+

Information Exposure

+
+ +
+ medium severity +
+ +
+ +
    +
  • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
  • +
  • + Package Manager: ubuntu:22.04 +
  • +
  • + Vulnerable module: + + libgcrypt20
  • Introduced through: - docker-image|quay.io/argoproj/argocd@latest and systemd/libsystemd0@249.11-0ubuntu3.6 + docker-image|quay.io/argoproj/argocd@latest and libgcrypt20@1.9.4-3ubuntu3
@@ -522,7 +672,7 @@

Detailed paths

Introduced through: docker-image|quay.io/argoproj/argocd@latest - systemd/libsystemd0@249.11-0ubuntu3.6 + libgcrypt20@1.9.4-3ubuntu3 @@ -531,9 +681,9 @@

Detailed paths

Introduced through: docker-image|quay.io/argoproj/argocd@latest - apt@2.4.8 + gnupg2/dirmngr@2.2.27-3ubuntu2.1 - systemd/libsystemd0@249.11-0ubuntu3.6 + libgcrypt20@1.9.4-3ubuntu3 @@ -542,9 +692,9 @@

Detailed paths

Introduced through: docker-image|quay.io/argoproj/argocd@latest - procps/libprocps8@2:3.3.17-6ubuntu2 + gnupg2/gpg@2.2.27-3ubuntu2.1 - systemd/libsystemd0@249.11-0ubuntu3.6 + libgcrypt20@1.9.4-3ubuntu3 @@ -553,77 +703,1693 @@

Detailed paths

Introduced through: docker-image|quay.io/argoproj/argocd@latest - util-linux@2.37.2-4ubuntu3 + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + libgcrypt20@1.9.4-3ubuntu3 + + + + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + apt@2.4.11 + + gnupg2/gpgv@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + gnupg2/gnupg@2.2.27-3ubuntu2.1 - systemd/libsystemd0@249.11-0ubuntu3.6 + gnupg2/gpgsm@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + libgcrypt20@1.9.4-3ubuntu3 -
  • + + + +
    + +
    + +

    NVD Description

    +

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

    +

    A timing-based side-channel flaw was found in libgcrypt's RSA implementation. This issue may allow a remote attacker to initiate a Bleichenbacher-style attack, which can lead to the decryption of RSA ciphertexts.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 libgcrypt20.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-26461

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@latest and krb5/libk5crypto3@1.19.2-2ubuntu0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + krb5/libkrb5support0@1.19.2-2ubuntu0.3 + + + +
    • +
    + +
    + +
    + +

    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.

    +

    Kerberos 5 (aka krb5) 1.21.2 contains a memory leak vulnerability in /krb5/src/lib/gssapi/krb5/k5sealv3.c.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-26462

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@latest and krb5/libk5crypto3@1.19.2-2ubuntu0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + krb5/libkrb5support0@1.19.2-2ubuntu0.3 + + + +
    • +
    + +
    + +
    + +

    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.

    +

    Kerberos 5 (aka krb5) 1.21.2 contains a memory leak vulnerability in /krb5/src/kdc/ndr.c.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-26458

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@latest and krb5/libk5crypto3@1.19.2-2ubuntu0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + krb5/libkrb5support0@1.19.2-2ubuntu0.3 + + + +
    • +
    + +
    + +
    + +

    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.

    +

    Kerberos 5 (aka krb5) 1.21.2 contains a memory leak in /krb5/src/lib/rpc/pmap_rmt.c.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    References

    + + +
    + + + +
    +
    +

    LGPL-3.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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

    + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/internal/encoding/json +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/protobuf/internal/encoding/json@v1.31.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + google.golang.org/protobuf/internal/encoding/json@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/internal/encoding/json to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Stack-based Buffer Overflow

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/protobuf/encoding/protojson@v1.31.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Stack-based Buffer Overflow when processing input that uses pathologically deep nesting.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.32.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/protobuf/encoding/protojson@v1.31.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Information Exposure

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gnutls28/libgnutls30 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@latest and gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + apt@2.4.11 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + openldap/libldap-2.5-0@2.5.17+dfsg-0ubuntu0.22.04.1 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + rtmpdump/librtmp1@2.4+20151223.gitfa8646d.1-2build4 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    A flaw was found in GnuTLS. The Minerva attack is a cryptographic vulnerability that exploits deterministic behavior in systems like GnuTLS, leading to side-channel leaks. In specific scenarios, such as when using the GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE flag, it can result in a noticeable step in nonce size from 513 to 512 bits, exposing a potential timing side-channel.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 gnutls28.

    +

    References

    + + +
    + + + +
    +
    +

    Uncaught Exception

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gnutls28/libgnutls30 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@latest and gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + apt@2.4.11 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + openldap/libldap-2.5-0@2.5.17+dfsg-0ubuntu0.22.04.1 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + rtmpdump/librtmp1@2.4+20151223.gitfa8646d.1-2build4 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    A flaw has been discovered in GnuTLS where an application crash can be induced when attempting to verify a specially crafted .pem bundle using the "certtool --verify-chain" command.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 gnutls28.

    +

    References

    + + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/helm/v3 /usr/local/bin/helm +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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: - docker-image|quay.io/argoproj/argocd@latest - - util-linux/bsdutils@1:2.37.2-4ubuntu3 + github.com/argoproj/argo-cd/v2@* - systemd/libsystemd0@249.11-0ubuntu3.6 + github.com/hashicorp/go-cleanhttp@v0.5.2
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - apt@2.4.8 - - apt/libapt-pkg6.0@2.4.8 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - +
    - -
  • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - systemd/libudev1@249.11-0ubuntu3.6 - - +
  • - -
  • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - libfido2/libfido2-1@1.10.0-1 - - systemd/libudev1@249.11-0ubuntu3.6 - - +
    + +

    MPL-2.0 license

    -
  • -
  • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - util-linux@2.37.2-4ubuntu3 - - systemd/libudev1@249.11-0ubuntu3.6 - - +
    -
  • + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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: - docker-image|quay.io/argoproj/argocd@latest - - apt@2.4.8 + github.com/argoproj/argo-cd/v2@* - apt/libapt-pkg6.0@2.4.8 - - systemd/libudev1@249.11-0ubuntu3.6 + github.com/gosimple/slug@v1.13.1 @@ -634,51 +2400,41 @@

      Detailed paths


      -

      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream systemd package.

      -

      An off-by-one Error issue was discovered in Systemd in format_timespan() function of time-util.c. An attacker could supply specific values for time and accuracy that leads to buffer overrun in format_timespan(), leading to a Denial of Service.

      -

      Remediation

      -

      There is no fixed version for Ubuntu:22.04 systemd.

      -

      References

      - +

      MPL-2.0 license


    -
    -

    Integer Overflow or Wraparound

    +
    +

    CVE-2023-7008

    -
    - medium severity +
    + low severity

      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • Package Manager: ubuntu:22.04
    • Vulnerable module: - krb5/libk5crypto3 + systemd/libsystemd0
    • Introduced through: - docker-image|quay.io/argoproj/argocd@latest and krb5/libk5crypto3@1.19.2-2 + docker-image|quay.io/argoproj/argocd@latest and systemd/libsystemd0@249.11-0ubuntu3.12
    @@ -693,7 +2449,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - krb5/libk5crypto3@1.19.2-2 + systemd/libsystemd0@249.11-0ubuntu3.12 @@ -702,19 +2458,9 @@

    Detailed paths

    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 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 + apt@2.4.11 - krb5/libk5crypto3@1.19.2-2 + systemd/libsystemd0@249.11-0ubuntu3.12 @@ -723,21 +2469,9 @@

    Detailed paths

    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 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 + procps/libprocps8@2:3.3.17-6ubuntu2.1 - krb5/libkrb5-3@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 + systemd/libsystemd0@249.11-0ubuntu3.12 @@ -746,7 +2480,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - krb5/libkrb5-3@1.19.2-2 + util-linux@2.37.2-4ubuntu3 + + systemd/libsystemd0@249.11-0ubuntu3.12 @@ -755,19 +2491,9 @@

    Detailed paths

    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 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 + util-linux/bsdutils@1:2.37.2-4ubuntu3 - krb5/libkrb5-3@1.19.2-2 + systemd/libsystemd0@249.11-0ubuntu3.12 @@ -776,18 +2502,11 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - krb5/libgssapi-krb5-2@1.19.2-2 - - - - -
  • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest + apt@2.4.11 - openssh/openssh-client@1:8.9p1-3ubuntu0.1 + apt/libapt-pkg6.0@2.4.11 - krb5/libgssapi-krb5-2@1.19.2-2 + systemd/libsystemd0@249.11-0ubuntu3.12 @@ -796,11 +2515,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - krb5/libgssapi-krb5-2@1.19.2-2 + systemd/libudev1@249.11-0ubuntu3.12 @@ -809,13 +2524,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - libssh/libssh-4@0.9.6-2build1 + libfido2/libfido2-1@1.10.0-1 - krb5/libgssapi-krb5-2@1.19.2-2 + systemd/libudev1@249.11-0ubuntu3.12 @@ -824,17 +2535,9 @@

    Detailed paths

    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 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + util-linux@2.37.2-4ubuntu3 - krb5/libgssapi-krb5-2@1.19.2-2 + systemd/libudev1@249.11-0ubuntu3.12 @@ -843,9 +2546,11 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - meta-common-packages@meta + apt@2.4.11 - krb5/libkrb5support0@1.19.2-2 + apt/libapt-pkg6.0@2.4.11 + + systemd/libudev1@249.11-0ubuntu3.12 @@ -857,31 +2562,31 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream krb5 package.

    -

    PAC parsing in MIT Kerberos 5 (aka krb5) before 1.19.4 and 1.20.x before 1.20.1 has integer overflows that may lead to remote code execution (in KDC, kadmind, or a GSS or Kerberos application server) on 32-bit platforms (which have a resultant heap-based buffer overflow), and cause a denial of service on other platforms. This occurs in krb5_pac_parse in lib/krb5/krb/pac.c. Heimdal before 7.7.1 has "a similar bug."

    +

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

    +

    A vulnerability was found in systemd-resolved. This issue may allow systemd-resolved to accept records of DNSSEC-signed domains even when they have no signature, allowing man-in-the-middles (or the upstream DNS resolver) to manipulate records.

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    There is no fixed version for Ubuntu:22.04 systemd.

    References


  • -

    CVE-2022-46908

    +

    Arbitrary Code Injection

    @@ -891,19 +2596,22 @@

    CVE-2022-46908


      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • Package Manager: ubuntu:22.04
    • Vulnerable module: - sqlite3/libsqlite3-0 + shadow/passwd
    • Introduced through: + docker-image|quay.io/argoproj/argocd@latest and shadow/passwd@1:4.8.1-2ubuntu2.2 - docker-image|quay.io/argoproj/argocd@latest, gnupg2/gpg@2.2.27-3ubuntu2.1 and others
    @@ -917,9 +2625,38 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - gnupg2/gpg@2.2.27-3ubuntu2.1 + shadow/passwd@1:4.8.1-2ubuntu2.2 + + + + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest - sqlite3/libsqlite3-0@3.37.2-2ubuntu0.1 + shadow/login@1:4.8.1-2ubuntu2.2 @@ -931,22 +2668,24 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream sqlite3 package.

    -

    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.

    +

    Note: Versions mentioned in the description apply only to the upstream shadow package and not the shadow package as distributed by Ubuntu. + 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 sqlite3.

    +

    There is no fixed version for Ubuntu:22.04 shadow.

    References


  • @@ -961,6 +2700,9 @@

    Uncontrolled Recursion


      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • Package Manager: ubuntu:22.04
    • @@ -1010,7 +2752,8 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream pcre3 package.

      +

      Note: Versions mentioned in the description apply only to the upstream pcre3 package and not the pcre3 package as distributed by Ubuntu. + 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.

      @@ -1022,6 +2765,9 @@

      References

    • MLIST
    • OSS security Advisory
    • Security Focus
    • +
    • cve@mitre.org
    • +
    • cve@mitre.org
    • +
    • cve@mitre.org

    @@ -1042,6 +2788,9 @@

    Release of Invalid Pointer or Reference


      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • Package Manager: ubuntu:22.04
    • @@ -1080,14 +2829,15 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream patch package.

      +

      Note: Versions mentioned in the description apply only to the upstream patch package and not the patch 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.

      Remediation

      There is no fixed version for Ubuntu:22.04 patch.

      References


      @@ -1108,6 +2858,9 @@

      Double Free


        +
      • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
      • Package Manager: ubuntu:22.04
      • @@ -1146,7 +2899,8 @@

        Detailed paths


        NVD Description

        -

        Note: Versions mentioned in the description apply to the upstream patch package.

        +

        Note: Versions mentioned in the description apply only to the upstream patch package and not the patch 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.

        Remediation

        There is no fixed version for Ubuntu:22.04 patch.

        @@ -1169,7 +2923,7 @@

        References

    -

    Improper Locking

    +

    CVE-2023-50495

    @@ -1179,18 +2933,21 @@

    Improper Locking


      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • Package Manager: ubuntu:22.04
    • Vulnerable module: - openssl/libssl3 + ncurses/libtinfo6
    • Introduced through: - docker-image|quay.io/argoproj/argocd@latest and openssl/libssl3@3.0.2-0ubuntu1.7 + docker-image|quay.io/argoproj/argocd@latest and ncurses/libtinfo6@6.3-2ubuntu0.1
    @@ -1205,7 +2962,84 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - openssl/libssl3@3.0.2-0ubuntu1.7 + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + bash@5.1-6ubuntu1.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + less@590-1ubuntu0.22.04.2 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + libedit/libedit2@3.1-20210910-1build1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + ncurses/libncurses6@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + ncurses/ncurses-bin@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1214,9 +3048,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - cyrus-sasl2/libsasl2-modules@2.1.27+dfsg2-3ubuntu1.1 + util-linux@2.37.2-4ubuntu3 - openssl/libssl3@3.0.2-0ubuntu1.7 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1225,9 +3059,13 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - libfido2/libfido2-1@1.10.0-1 + gnupg2/gpg@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + readline/libreadline8@8.1.2-1 - openssl/libssl3@3.0.2-0ubuntu1.7 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1236,9 +3074,13 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - openssh/openssh-client@1:8.9p1-3ubuntu0.1 + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + pinentry/pinentry-curses@1.1.1-1build2 - openssl/libssl3@3.0.2-0ubuntu1.7 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1247,11 +3089,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - ca-certificates@20211016ubuntu0.22.04.1 - - openssl@3.0.2-0ubuntu1.7 - - openssl/libssl3@3.0.2-0ubuntu1.7 + ncurses/libncursesw6@6.3-2ubuntu0.1 @@ -1260,13 +3098,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 + procps@2:3.3.17-6ubuntu2.1 - libssh/libssh-4@0.9.6-2build1 - - openssl/libssl3@3.0.2-0ubuntu1.7 + ncurses/libncursesw6@6.3-2ubuntu0.1 @@ -1275,21 +3109,13 @@

    Detailed paths

    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 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + gnupg2/gnupg@2.2.27-3ubuntu2.1 - krb5/libgssapi-krb5-2@1.19.2-2 + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - krb5/libkrb5-3@1.19.2-2 + pinentry/pinentry-curses@1.1.1-1build2 - openssl/libssl3@3.0.2-0ubuntu1.7 + ncurses/libncursesw6@6.3-2ubuntu0.1 @@ -1298,7 +3124,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - openssl@3.0.2-0ubuntu1.7 + ncurses/libncurses6@6.3-2ubuntu0.1 @@ -1307,152 +3133,27 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - ca-certificates@20211016ubuntu0.22.04.1 + procps@2:3.3.17-6ubuntu2.1 - openssl@3.0.2-0ubuntu1.7 + ncurses/libncurses6@6.3-2ubuntu0.1
  • - - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssl package.

    -

    If an X.509 certificate contains a malformed policy constraint and policy processing is enabled, then a write lock will be taken twice recursively. On some operating systems (most widely: Windows) this results in a denial of service when the affected process hangs. Policy processing being enabled on a publicly facing server is not considered to be a common setup. Policy processing is enabled by passing the -policy&#39; argument to the command line utilities or by calling either X509_VERIFY_PARAM_add0_policy()' or `X509_VERIFY_PARAM_set1_policies()' functions.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssl.

    -

    References

    - - -
    - - - -
    -
    -

    CVE-2021-41617

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - openssh/openssh-client -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@latest and openssh/openssh-client@1:8.9p1-3ubuntu0.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
    • Introduced through: docker-image|quay.io/argoproj/argocd@latest - openssh/openssh-client@1:8.9p1-3ubuntu0.1 + ncurses/ncurses-base@6.3-2ubuntu0.1
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssh package.

    -

    sshd in OpenSSH 6.2 through 8.x before 8.8, when certain non-default configurations are used, allows privilege escalation because supplemental groups are not initialized as expected. Helper programs for AuthorizedKeysCommand and AuthorizedPrincipalsCommand may run with privileges associated with group memberships of the sshd process, if the configuration specifies running the command as a different user.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssh.

    -

    References

    - - -
    - - - -
    -
    -

    Information Exposure

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - openssh/openssh-client -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@latest and openssh/openssh-client@1:8.9p1-3ubuntu0.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
    -

    Out-of-bounds Read

    +

    CVE-2023-45918

    @@ -1499,6 +3197,9 @@

    Out-of-bounds Read


      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • Package Manager: ubuntu:22.04
    • @@ -1510,7 +3211,7 @@

      Out-of-bounds Read

    • Introduced through: - docker-image|quay.io/argoproj/argocd@latest and ncurses/libtinfo6@6.3-2 + docker-image|quay.io/argoproj/argocd@latest and ncurses/libtinfo6@6.3-2ubuntu0.1
    @@ -1525,7 +3226,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - ncurses/libtinfo6@6.3-2 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1534,9 +3235,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - bash@5.1-6ubuntu1 + bash@5.1-6ubuntu1.1 - ncurses/libtinfo6@6.3-2 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1545,9 +3246,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - ncurses/libncursesw6@6.3-2 + ncurses/libncursesw6@6.3-2ubuntu0.1 - ncurses/libtinfo6@6.3-2 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1556,9 +3257,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - less@590-1build1 + less@590-1ubuntu0.22.04.2 - ncurses/libtinfo6@6.3-2 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1569,7 +3270,7 @@

    Detailed paths

    libedit/libedit2@3.1-20210910-1build1 - ncurses/libtinfo6@6.3-2 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1578,9 +3279,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - ncurses/libncurses6@6.3-2 + ncurses/libncurses6@6.3-2ubuntu0.1 - ncurses/libtinfo6@6.3-2 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1589,9 +3290,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - ncurses/ncurses-bin@6.3-2 + ncurses/ncurses-bin@6.3-2ubuntu0.1 - ncurses/libtinfo6@6.3-2 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1600,9 +3301,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - procps@2:3.3.17-6ubuntu2 + procps@2:3.3.17-6ubuntu2.1 - ncurses/libtinfo6@6.3-2 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1613,7 +3314,7 @@

    Detailed paths

    util-linux@2.37.2-4ubuntu3 - ncurses/libtinfo6@6.3-2 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1628,7 +3329,7 @@

    Detailed paths

    readline/libreadline8@8.1.2-1 - ncurses/libtinfo6@6.3-2 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1643,7 +3344,7 @@

    Detailed paths

    pinentry/pinentry-curses@1.1.1-1build2 - ncurses/libtinfo6@6.3-2 + ncurses/libtinfo6@6.3-2ubuntu0.1 @@ -1652,7 +3353,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - ncurses/libncursesw6@6.3-2 + ncurses/libncursesw6@6.3-2ubuntu0.1 @@ -1661,9 +3362,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - procps@2:3.3.17-6ubuntu2 + procps@2:3.3.17-6ubuntu2.1 - ncurses/libncursesw6@6.3-2 + ncurses/libncursesw6@6.3-2ubuntu0.1 @@ -1678,7 +3379,7 @@

    Detailed paths

    pinentry/pinentry-curses@1.1.1-1build2 - ncurses/libncursesw6@6.3-2 + ncurses/libncursesw6@6.3-2ubuntu0.1 @@ -1687,7 +3388,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - ncurses/libncurses6@6.3-2 + ncurses/libncurses6@6.3-2ubuntu0.1 @@ -1696,9 +3397,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - procps@2:3.3.17-6ubuntu2 + procps@2:3.3.17-6ubuntu2.1 - ncurses/libncurses6@6.3-2 + ncurses/libncurses6@6.3-2ubuntu0.1 @@ -1707,7 +3408,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - ncurses/ncurses-base@6.3-2 + ncurses/ncurses-base@6.3-2ubuntu0.1 @@ -1716,7 +3417,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - ncurses/ncurses-bin@6.3-2 + ncurses/ncurses-bin@6.3-2ubuntu0.1 @@ -1728,24 +3429,99 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream ncurses package.

    -

    ncurses 6.3 before patch 20220416 has an out-of-bounds read and segmentation violation in convert_strings in tinfo/read_entry.c in the terminfo library.

    +

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

    +

    ncurses 6.4-20230610 has a NULL pointer dereference in tgetstr in tinfo/lib_termcap.c.

    Remediation

    There is no fixed version for Ubuntu:22.04 ncurses.

    References

    + +
    + + + +
    +
    +

    Resource Exhaustion

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + libzstd/libzstd1 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@latest and libzstd/libzstd1@1.4.8+dfsg-3build1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + 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

    +
    @@ -1760,6 +3536,9 @@

    Integer Overflow or Wraparound


      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • Package Manager: ubuntu:22.04
    • @@ -1771,7 +3550,7 @@

      Integer Overflow or Wraparound

    • Introduced through: - docker-image|quay.io/argoproj/argocd@latest and krb5/libk5crypto3@1.19.2-2 + docker-image|quay.io/argoproj/argocd@latest and krb5/libk5crypto3@1.19.2-2ubuntu0.3
    @@ -1786,7 +3565,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - krb5/libk5crypto3@1.19.2-2 + krb5/libk5crypto3@1.19.2-2ubuntu0.3 @@ -1797,17 +3576,17 @@

    Detailed paths

    adduser@3.118ubuntu5 - shadow/passwd@1:4.8.1-2ubuntu2.1 + shadow/passwd@1:4.8.1-2ubuntu2.2 - pam/libpam-modules@1.4.0-11ubuntu2 + pam/libpam-modules@1.4.0-11ubuntu2.4 libnsl/libnsl2@1.3.0-2build2 libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - krb5/libgssapi-krb5-2@1.19.2-2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 - krb5/libk5crypto3@1.19.2-2 + krb5/libk5crypto3@1.19.2-2ubuntu0.3 @@ -1818,19 +3597,19 @@

    Detailed paths

    adduser@3.118ubuntu5 - shadow/passwd@1:4.8.1-2ubuntu2.1 + shadow/passwd@1:4.8.1-2ubuntu2.2 - pam/libpam-modules@1.4.0-11ubuntu2 + pam/libpam-modules@1.4.0-11ubuntu2.4 libnsl/libnsl2@1.3.0-2build2 libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - krb5/libgssapi-krb5-2@1.19.2-2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 - krb5/libkrb5-3@1.19.2-2 + krb5/libkrb5-3@1.19.2-2ubuntu0.3 - krb5/libk5crypto3@1.19.2-2 + krb5/libk5crypto3@1.19.2-2ubuntu0.3 @@ -1839,7 +3618,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - krb5/libkrb5-3@1.19.2-2 + krb5/libkrb5-3@1.19.2-2ubuntu0.3 @@ -1850,17 +3629,17 @@

    Detailed paths

    adduser@3.118ubuntu5 - shadow/passwd@1:4.8.1-2ubuntu2.1 + shadow/passwd@1:4.8.1-2ubuntu2.2 - pam/libpam-modules@1.4.0-11ubuntu2 + pam/libpam-modules@1.4.0-11ubuntu2.4 libnsl/libnsl2@1.3.0-2build2 libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - krb5/libgssapi-krb5-2@1.19.2-2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 - krb5/libkrb5-3@1.19.2-2 + krb5/libkrb5-3@1.19.2-2ubuntu0.3 @@ -1869,7 +3648,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - krb5/libgssapi-krb5-2@1.19.2-2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 @@ -1878,9 +3657,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - openssh/openssh-client@1:8.9p1-3ubuntu0.1 + openssh/openssh-client@1:8.9p1-3ubuntu0.6 - krb5/libgssapi-krb5-2@1.19.2-2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 @@ -1889,11 +3668,11 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - git@1:2.34.1-1ubuntu1.6 + git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - krb5/libgssapi-krb5-2@1.19.2-2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 @@ -1902,13 +3681,13 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - git@1:2.34.1-1ubuntu1.6 + git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - libssh/libssh-4@0.9.6-2build1 + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 - krb5/libgssapi-krb5-2@1.19.2-2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 @@ -1919,15 +3698,15 @@

    Detailed paths

    adduser@3.118ubuntu5 - shadow/passwd@1:4.8.1-2ubuntu2.1 + shadow/passwd@1:4.8.1-2ubuntu2.2 - pam/libpam-modules@1.4.0-11ubuntu2 + pam/libpam-modules@1.4.0-11ubuntu2.4 libnsl/libnsl2@1.3.0-2build2 libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - krb5/libgssapi-krb5-2@1.19.2-2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 @@ -1936,9 +3715,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - meta-common-packages@meta - - krb5/libkrb5support0@1.19.2-2 + krb5/libkrb5support0@1.19.2-2ubuntu0.3 @@ -1950,17 +3727,19 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream krb5 package.

    +

    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.

    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


    @@ -1971,7 +3750,7 @@

    References

    -

    CVE-2022-3219

    +

    Out-of-bounds Write

    @@ -1981,6 +3760,9 @@

    CVE-2022-3219


      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • Package Manager: ubuntu:22.04
    • @@ -2016,7 +3798,7 @@

      Detailed paths

      Introduced through: docker-image|quay.io/argoproj/argocd@latest - apt@2.4.8 + apt@2.4.11 gnupg2/gpgv@2.2.27-3ubuntu2.1 @@ -2323,12 +4105,20 @@

      Detailed paths


      NVD Description

      -

      This vulnerability has not been analyzed by NVD yet.

      +

      Note: Versions mentioned in the description apply only to the upstream gnupg2 package and not the gnupg2 package as distributed by Ubuntu. + 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


      @@ -2349,6 +4139,9 @@

      Allocation of Resources Without Limits or Throttling

        +
      • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
      • Package Manager: ubuntu:22.04
      • @@ -2360,7 +4153,7 @@

        Allocation of Resources Without Limits or Throttling

        Introduced through: - docker-image|quay.io/argoproj/argocd@latest and glibc/libc-bin@2.35-0ubuntu3.1 + docker-image|quay.io/argoproj/argocd@latest and glibc/libc-bin@2.35-0ubuntu3.6
      @@ -2375,7 +4168,7 @@

      Detailed paths

      Introduced through: docker-image|quay.io/argoproj/argocd@latest - glibc/libc-bin@2.35-0ubuntu3.1 + glibc/libc-bin@2.35-0ubuntu3.6 @@ -2384,9 +4177,7 @@

      Detailed paths

      Introduced through: docker-image|quay.io/argoproj/argocd@latest - meta-common-packages@meta - - glibc/libc6@2.35-0ubuntu3.1 + glibc/libc6@2.35-0ubuntu3.6 @@ -2398,16 +4189,17 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream glibc package.

      +

      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.

      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


      @@ -2428,6 +4220,9 @@

      Improper Input Validation


        +
      • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
      • Package Manager: ubuntu:22.04
      • @@ -2440,7 +4235,7 @@

        Improper Input Validation

      • Introduced through: - docker-image|quay.io/argoproj/argocd@latest, git@1:2.34.1-1ubuntu1.6 and others + docker-image|quay.io/argoproj/argocd@latest, git@1:2.34.1-1ubuntu1.10 and others
      @@ -2454,9 +4249,9 @@

      Detailed paths

      Introduced through: docker-image|quay.io/argoproj/argocd@latest - git@1:2.34.1-1ubuntu1.6 + git@1:2.34.1-1ubuntu1.10 - git/git-man@1:2.34.1-1ubuntu1.6 + git/git-man@1:2.34.1-1ubuntu1.10 @@ -2465,7 +4260,7 @@

      Detailed paths

      Introduced through: docker-image|quay.io/argoproj/argocd@latest - git@1:2.34.1-1ubuntu1.6 + git@1:2.34.1-1ubuntu1.10 @@ -2474,9 +4269,9 @@

      Detailed paths

      Introduced through: docker-image|quay.io/argoproj/argocd@latest - git-lfs@3.0.2-1 + git-lfs@3.0.2-1ubuntu0.2 - git@1:2.34.1-1ubuntu1.6 + git@1:2.34.1-1ubuntu1.10 @@ -2488,7 +4283,8 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream git package.

      +

      Note: Versions mentioned in the description apply only to the upstream git package and not the git package as distributed by Ubuntu. + 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.

      @@ -2507,7 +4303,7 @@

      References

    -

    Improper Input Validation

    +

    Uncontrolled Recursion

    @@ -2517,18 +4313,21 @@

    Improper Input Validation


      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • Package Manager: ubuntu:22.04
    • Vulnerable module: - coreutils + gcc-12/libstdc++6
    • Introduced through: - docker-image|quay.io/argoproj/argocd@latest and coreutils@8.32-4.1ubuntu1 + docker-image|quay.io/argoproj/argocd@latest and gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04
    @@ -2543,7 +4342,49 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - coreutils@8.32-4.1ubuntu1 + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + + + + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + apt@2.4.11 + + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + gcc-12/gcc-12-base@12.3.0-1ubuntu1~22.04 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + gcc-12/libgcc-s1@12.3.0-1ubuntu1~22.04 @@ -2555,28 +4396,29 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream coreutils package.

    -

    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.

    +

    Note: Versions mentioned in the description apply only to the upstream gcc-12 package and not the gcc-12 package as distributed by Ubuntu. + 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 coreutils.

    +

    There is no fixed version for Ubuntu:22.04 gcc-12.

    References


  • -

    Out-of-bounds Write

    +

    Improper Input Validation

    @@ -2586,18 +4428,21 @@

    Out-of-bounds Write


      +
    • + Manifest file: quay.io/argoproj/argocd:latest/argoproj/argocd Dockerfile +
    • Package Manager: ubuntu:22.04
    • Vulnerable module: - bash + coreutils
    • Introduced through: - docker-image|quay.io/argoproj/argocd@latest and bash@5.1-6ubuntu1 + docker-image|quay.io/argoproj/argocd@latest and coreutils@8.32-4.1ubuntu1.1
    @@ -2612,7 +4457,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - bash@5.1-6ubuntu1 + coreutils@8.32-4.1ubuntu1.1 @@ -2624,20 +4469,25 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream bash package.

    -

    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.

    +

    Note: Versions mentioned in the description apply only to the upstream coreutils package and not the coreutils package as distributed by Ubuntu. + 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 bash.

    +

    There is no fixed version for Ubuntu:22.04 coreutils.

    References


    diff --git a/docs/snyk/master/redis_7.0.14-alpine.html b/docs/snyk/master/redis_7.0.14-alpine.html new file mode 100644 index 0000000000000..f47d4fe717527 --- /dev/null +++ b/docs/snyk/master/redis_7.0.14-alpine.html @@ -0,0 +1,993 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    March 24th 2024, 12:15:59 am (UTC+00:00)

    +
    +
    + Scanned the following paths: +
      +
    • redis:7.0.14-alpine (apk)
    • +
    • redis:7.0.14-alpine/tianon/gosu//usr/local/bin/gosu (gomodules)
    • +
    +
    + +
    +
    3 known vulnerabilities
    +
    27 vulnerable dependency paths
    +
    19 dependencies
    +
    +
    +
    +
    + +
    +
    +
    +

    Out-of-bounds Write

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.19 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.14-alpine and openssl/libcrypto3@3.1.4-r2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + busybox/ssl_client@1.36.1-r15 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libssl3@3.1.4-r2 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + busybox/ssl_client@1.36.1-r15 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    + +
    + +
    + +

    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.19 relevant fixed versions and status.

    +

    Issue summary: The POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

    +

    Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

    +

    The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

    +

    The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

    +

    The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

    +

    Remediation

    +

    Upgrade Alpine:3.19 openssl to version 3.1.4-r3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-0727

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.19 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.14-alpine and openssl/libcrypto3@3.1.4-r2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + busybox/ssl_client@1.36.1-r15 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libssl3@3.1.4-r2 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + busybox/ssl_client@1.36.1-r15 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    + +
    + +
    + +

    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.19 relevant fixed versions and status.

    +

    Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

    +

    Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

    +

    A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

    +

    OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

    +

    We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

    +

    The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.19 openssl to version 3.1.4-r5 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-6237

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.19 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.14-alpine and openssl/libcrypto3@3.1.4-r2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + busybox/ssl_client@1.36.1-r15 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libssl3@3.1.4-r2 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + busybox/ssl_client@1.36.1-r15 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    This vulnerability has not been analyzed by NVD yet.

    +

    Remediation

    +

    Upgrade Alpine:3.19 openssl to version 3.1.4-r4 or higher.

    + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/master/redis_7.0.7-alpine.html b/docs/snyk/master/redis_7.0.7-alpine.html deleted file mode 100644 index 0cbbce3dd9b09..0000000000000 --- a/docs/snyk/master/redis_7.0.7-alpine.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:16:03 am

    -
    -
    - Scanned the following path: -
      -
    • redis:7.0.7-alpine (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    18 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|redis
    Path redis:7.0.7-alpine
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.3.13/argocd-iac-install.html b/docs/snyk/v2.3.13/argocd-iac-install.html deleted file mode 100644 index 91bfb11773e3b..0000000000000 --- a/docs/snyk/v2.3.13/argocd-iac-install.html +++ /dev/null @@ -1,3251 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:24:51 am

    -
    -
    - Scanned the following path: -
      -
    • /argo-cd/manifests/install.yaml (Kubernetes)
    • -
    -
    - -
    -
    50 total issues
    -
    -
    -
    -
    - -
    - - - - - - -
    Project manifests/install.yaml
    Path /argo-cd/manifests/install.yaml
    Project Type Kubernetes
    -
    -
    -
    -

    Container does not drop all default capabilities

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-6 -
    • - -
    • Introduced through: - [DocId: 41] - - input - - spec - - template - - spec - - containers[argocd-applicationset-controller] - - securityContext - - capabilities - - drop - -
    • - -
    • - Line number: 9800 -
    • -
    - -
    - -

    Impact

    -

    Containers are running with potentially unnecessary privileges

    - -

    Remediation

    -

    Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`

    - - -
    -
    - - - -
    -
    -

    Container does not drop all default capabilities

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-6 -
    • - -
    • Introduced through: - [DocId: 42] - - input - - spec - - template - - spec - - containers[dex] - - securityContext - - capabilities - - drop - -
    • - -
    • - Line number: 9874 -
    • -
    - -
    - -

    Impact

    -

    Containers are running with potentially unnecessary privileges

    - -

    Remediation

    -

    Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`

    - - -
    -
    - - - -
    -
    -

    Container does not drop all default capabilities

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-6 -
    • - -
    • Introduced through: - [DocId: 42] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - capabilities - - drop - -
    • - -
    • - Line number: 9884 -
    • -
    - -
    - -

    Impact

    -

    Containers are running with potentially unnecessary privileges

    - -

    Remediation

    -

    Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`

    - - -
    -
    - - - -
    -
    -

    Container does not drop all default capabilities

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-6 -
    • - -
    • Introduced through: - [DocId: 43] - - input - - spec - - template - - spec - - containers[argocd-notifications-controller] - - securityContext - - capabilities - - drop - -
    • - -
    • - Line number: 9920 -
    • -
    - -
    - -

    Impact

    -

    Containers are running with potentially unnecessary privileges

    - -

    Remediation

    -

    Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`

    - - -
    -
    - - - -
    -
    -

    Container does not drop all default capabilities

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-6 -
    • - -
    • Introduced through: - [DocId: 44] - - input - - spec - - template - - spec - - containers[redis] - - securityContext - - capabilities - - drop - -
    • - -
    • - Line number: 9986 -
    • -
    - -
    - -

    Impact

    -

    Containers are running with potentially unnecessary privileges

    - -

    Remediation

    -

    Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`

    - - -
    -
    - - - -
    -
    -

    Container does not drop all default capabilities

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-6 -
    • - -
    • Introduced through: - [DocId: 45] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - capabilities - - drop - -
    • - -
    • - Line number: 10169 -
    • -
    - -
    - -

    Impact

    -

    Containers are running with potentially unnecessary privileges

    - -

    Remediation

    -

    Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`

    - - -
    -
    - - - -
    -
    -

    Container is running without privilege escalation control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-9 -
    • - -
    • Introduced through: - [DocId: 41] - - input - - spec - - template - - spec - - containers[argocd-applicationset-controller] - - securityContext - - allowPrivilegeEscalation - -
    • - -
    • - Line number: 9800 -
    • -
    - -
    - -

    Impact

    -

    Processes could elevate current privileges via known vectors, for example SUID binaries

    - -

    Remediation

    -

    Set `securityContext.allowPrivilegeEscalation` to `false`

    - - -
    -
    - - - -
    -
    -

    Container is running without privilege escalation control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-9 -
    • - -
    • Introduced through: - [DocId: 42] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - allowPrivilegeEscalation - -
    • - -
    • - Line number: 9884 -
    • -
    - -
    - -

    Impact

    -

    Processes could elevate current privileges via known vectors, for example SUID binaries

    - -

    Remediation

    -

    Set `securityContext.allowPrivilegeEscalation` to `false`

    - - -
    -
    - - - -
    -
    -

    Container is running without privilege escalation control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-9 -
    • - -
    • Introduced through: - [DocId: 43] - - input - - spec - - template - - spec - - containers[argocd-notifications-controller] - - securityContext - - allowPrivilegeEscalation - -
    • - -
    • - Line number: 9920 -
    • -
    - -
    - -

    Impact

    -

    Processes could elevate current privileges via known vectors, for example SUID binaries

    - -

    Remediation

    -

    Set `securityContext.allowPrivilegeEscalation` to `false`

    - - -
    -
    - - - -
    -
    -

    Container is running without privilege escalation control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-9 -
    • - -
    • Introduced through: - [DocId: 44] - - input - - spec - - template - - spec - - containers[redis] - - securityContext - - allowPrivilegeEscalation - -
    • - -
    • - Line number: 9986 -
    • -
    - -
    - -

    Impact

    -

    Processes could elevate current privileges via known vectors, for example SUID binaries

    - -

    Remediation

    -

    Set `securityContext.allowPrivilegeEscalation` to `false`

    - - -
    -
    - - - -
    -
    -

    Container is running without privilege escalation control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-9 -
    • - -
    • Introduced through: - [DocId: 45] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - allowPrivilegeEscalation - -
    • - -
    • - Line number: 10169 -
    • -
    - -
    - -

    Impact

    -

    Processes could elevate current privileges via known vectors, for example SUID binaries

    - -

    Remediation

    -

    Set `securityContext.allowPrivilegeEscalation` to `false`

    - - -
    -
    - - - -
    -
    -

    Container is running without root user control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-10 -
    • - -
    • Introduced through: - [DocId: 41] - - input - - spec - - template - - spec - - containers[argocd-applicationset-controller] - - securityContext - - runAsNonRoot - -
    • - -
    • - Line number: 9800 -
    • -
    - -
    - -

    Impact

    -

    Container could be running with full administrative privileges

    - -

    Remediation

    -

    Set `securityContext.runAsNonRoot` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running without root user control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-10 -
    • - -
    • Introduced through: - [DocId: 42] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - runAsNonRoot - -
    • - -
    • - Line number: 9884 -
    • -
    - -
    - -

    Impact

    -

    Container could be running with full administrative privileges

    - -

    Remediation

    -

    Set `securityContext.runAsNonRoot` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running without root user control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-10 -
    • - -
    • Introduced through: - [DocId: 45] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - runAsNonRoot - -
    • - -
    • - Line number: 10169 -
    • -
    - -
    - -

    Impact

    -

    Container could be running with full administrative privileges

    - -

    Remediation

    -

    Set `securityContext.runAsNonRoot` to `true`

    - - -
    -
    - - - -
    -
    -

    Role with dangerous permissions

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-47 -
    • - -
    • Introduced through: - [DocId: 9] - - rules[0] - - resources - -
    • - -
    • - Line number: 9184 -
    • -
    - -
    - -

    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: 9256 -
    • -
    - -
    - -

    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: 9284 -
    • -
    - -
    - -

    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[3] - - resources - -
    • - -
    • - Line number: 9328 -
    • -
    - -
    - -

    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[1] - - resources - -
    • - -
    • - Line number: 9310 -
    • -
    - -
    - -

    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[0] - - resources - -
    • - -
    • - Line number: 9344 -
    • -
    - -
    - -

    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: 10169 -
    • -
    - -
    - -

    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: 9800 -
    • -
    - -
    - -

    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: 9884 -
    • -
    - -
    - -

    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: 9864 -
    • -
    - -
    - -

    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: 9920 -
    • -
    - -
    - -

    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: 9986 -
    • -
    - -
    - -

    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: 10169 -
    • -
    - -
    - -

    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: 10035 -
    • -
    - -
    - -

    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: 10244 -
    • -
    - -
    - -

    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: 10494 -
    • -
    - -
    - -

    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: 9871 -
    • -
    - -
    - -

    Impact

    -

    Increases the attack surface of the application and the container.

    - -

    Remediation

    -

    Reduce `ports` count to 2

    - - -
    -
    - - - -
    -
    -

    Container is running with writable root filesystem

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-8 -
    • - -
    • Introduced through: - [DocId: 41] - - input - - spec - - template - - spec - - containers[argocd-applicationset-controller] - - securityContext - - readOnlyRootFilesystem - -
    • - -
    • - Line number: 9800 -
    • -
    - -
    - -

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    - -

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running with writable root filesystem

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-8 -
    • - -
    • Introduced through: - [DocId: 42] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - readOnlyRootFilesystem - -
    • - -
    • - Line number: 9884 -
    • -
    - -
    - -

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    - -

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running with writable root filesystem

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-8 -
    • - -
    • Introduced through: - [DocId: 43] - - input - - spec - - template - - spec - - containers[argocd-notifications-controller] - - securityContext - - readOnlyRootFilesystem - -
    • - -
    • - Line number: 9920 -
    • -
    - -
    - -

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    - -

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running with writable root filesystem

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-8 -
    • - -
    • Introduced through: - [DocId: 44] - - input - - spec - - template - - spec - - containers[redis] - - securityContext - - readOnlyRootFilesystem - -
    • - -
    • - Line number: 9986 -
    • -
    - -
    - -

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    - -

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running with writable root filesystem

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-8 -
    • - -
    • Introduced through: - [DocId: 45] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - readOnlyRootFilesystem - -
    • - -
    • - Line number: 10169 -
    • -
    - -
    - -

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    - -

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    - - -
    -
    - - - -
    -
    -

    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: 9800 -
    • -
    - -
    - -

    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: 9864 -
    • -
    - -
    - -

    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: 9884 -
    • -
    - -
    - -

    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: 9986 -
    • -
    - -
    - -

    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: 10169 -
    • -
    - -
    - -

    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: 9800 -
    • -
    - -
    - -

    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: 9864 -
    • -
    - -
    - -

    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: 9884 -
    • -
    - -
    - -

    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: 9920 -
    • -
    - -
    - -

    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: 9986 -
    • -
    - -
    - -

    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: 10169 -
    • -
    - -
    - -

    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: 10035 -
    • -
    - -
    - -

    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: 10244 -
    • -
    - -
    - -

    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: 10494 -
    • -
    - -
    - -

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    - -

    Remediation

    -

    Set `resources.limits.memory` value

    - - -
    -
    - - - -
    -
    -
    - -
    - - - diff --git a/docs/snyk/v2.3.13/argocd-iac-namespace-install.html b/docs/snyk/v2.3.13/argocd-iac-namespace-install.html deleted file mode 100644 index b67dcb0a6e068..0000000000000 --- a/docs/snyk/v2.3.13/argocd-iac-namespace-install.html +++ /dev/null @@ -1,3251 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:25:20 am

    -
    -
    - Scanned the following path: -
      -
    • /argo-cd/manifests/namespace-install.yaml (Kubernetes)
    • -
    -
    - -
    -
    50 total issues
    -
    -
    -
    -
    - -
    - - - - - - -
    Project manifests/namespace-install.yaml
    Path /argo-cd/manifests/namespace-install.yaml
    Project Type Kubernetes
    -
    -
    -
    -

    Container does not drop all default capabilities

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-6 -
    • - -
    • Introduced through: - [DocId: 35] - - input - - spec - - template - - spec - - containers[argocd-applicationset-controller] - - securityContext - - capabilities - - drop - -
    • - -
    • - Line number: 7096 -
    • -
    - -
    - -

    Impact

    -

    Containers are running with potentially unnecessary privileges

    - -

    Remediation

    -

    Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`

    - - -
    -
    - - - -
    -
    -

    Container does not drop all default capabilities

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-6 -
    • - -
    • Introduced through: - [DocId: 36] - - input - - spec - - template - - spec - - containers[dex] - - securityContext - - capabilities - - drop - -
    • - -
    • - Line number: 7170 -
    • -
    - -
    - -

    Impact

    -

    Containers are running with potentially unnecessary privileges

    - -

    Remediation

    -

    Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`

    - - -
    -
    - - - -
    -
    -

    Container does not drop all default capabilities

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-6 -
    • - -
    • Introduced through: - [DocId: 36] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - capabilities - - drop - -
    • - -
    • - Line number: 7180 -
    • -
    - -
    - -

    Impact

    -

    Containers are running with potentially unnecessary privileges

    - -

    Remediation

    -

    Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`

    - - -
    -
    - - - -
    -
    -

    Container does not drop all default capabilities

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-6 -
    • - -
    • Introduced through: - [DocId: 37] - - input - - spec - - template - - spec - - containers[argocd-notifications-controller] - - securityContext - - capabilities - - drop - -
    • - -
    • - Line number: 7216 -
    • -
    - -
    - -

    Impact

    -

    Containers are running with potentially unnecessary privileges

    - -

    Remediation

    -

    Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`

    - - -
    -
    - - - -
    -
    -

    Container does not drop all default capabilities

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-6 -
    • - -
    • Introduced through: - [DocId: 38] - - input - - spec - - template - - spec - - containers[redis] - - securityContext - - capabilities - - drop - -
    • - -
    • - Line number: 7282 -
    • -
    - -
    - -

    Impact

    -

    Containers are running with potentially unnecessary privileges

    - -

    Remediation

    -

    Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`

    - - -
    -
    - - - -
    -
    -

    Container does not drop all default capabilities

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-6 -
    • - -
    • Introduced through: - [DocId: 39] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - capabilities - - drop - -
    • - -
    • - Line number: 7465 -
    • -
    - -
    - -

    Impact

    -

    Containers are running with potentially unnecessary privileges

    - -

    Remediation

    -

    Add `ALL` to `securityContext.capabilities.drop` list, and add only required capabilities in `securityContext.capabilities.add`

    - - -
    -
    - - - -
    -
    -

    Container is running without privilege escalation control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-9 -
    • - -
    • Introduced through: - [DocId: 35] - - input - - spec - - template - - spec - - containers[argocd-applicationset-controller] - - securityContext - - allowPrivilegeEscalation - -
    • - -
    • - Line number: 7096 -
    • -
    - -
    - -

    Impact

    -

    Processes could elevate current privileges via known vectors, for example SUID binaries

    - -

    Remediation

    -

    Set `securityContext.allowPrivilegeEscalation` to `false`

    - - -
    -
    - - - -
    -
    -

    Container is running without privilege escalation control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-9 -
    • - -
    • Introduced through: - [DocId: 36] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - allowPrivilegeEscalation - -
    • - -
    • - Line number: 7180 -
    • -
    - -
    - -

    Impact

    -

    Processes could elevate current privileges via known vectors, for example SUID binaries

    - -

    Remediation

    -

    Set `securityContext.allowPrivilegeEscalation` to `false`

    - - -
    -
    - - - -
    -
    -

    Container is running without privilege escalation control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-9 -
    • - -
    • Introduced through: - [DocId: 37] - - input - - spec - - template - - spec - - containers[argocd-notifications-controller] - - securityContext - - allowPrivilegeEscalation - -
    • - -
    • - Line number: 7216 -
    • -
    - -
    - -

    Impact

    -

    Processes could elevate current privileges via known vectors, for example SUID binaries

    - -

    Remediation

    -

    Set `securityContext.allowPrivilegeEscalation` to `false`

    - - -
    -
    - - - -
    -
    -

    Container is running without privilege escalation control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-9 -
    • - -
    • Introduced through: - [DocId: 38] - - input - - spec - - template - - spec - - containers[redis] - - securityContext - - allowPrivilegeEscalation - -
    • - -
    • - Line number: 7282 -
    • -
    - -
    - -

    Impact

    -

    Processes could elevate current privileges via known vectors, for example SUID binaries

    - -

    Remediation

    -

    Set `securityContext.allowPrivilegeEscalation` to `false`

    - - -
    -
    - - - -
    -
    -

    Container is running without privilege escalation control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-9 -
    • - -
    • Introduced through: - [DocId: 39] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - allowPrivilegeEscalation - -
    • - -
    • - Line number: 7465 -
    • -
    - -
    - -

    Impact

    -

    Processes could elevate current privileges via known vectors, for example SUID binaries

    - -

    Remediation

    -

    Set `securityContext.allowPrivilegeEscalation` to `false`

    - - -
    -
    - - - -
    -
    -

    Container is running without root user control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-10 -
    • - -
    • Introduced through: - [DocId: 35] - - input - - spec - - template - - spec - - containers[argocd-applicationset-controller] - - securityContext - - runAsNonRoot - -
    • - -
    • - Line number: 7096 -
    • -
    - -
    - -

    Impact

    -

    Container could be running with full administrative privileges

    - -

    Remediation

    -

    Set `securityContext.runAsNonRoot` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running without root user control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-10 -
    • - -
    • Introduced through: - [DocId: 36] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - runAsNonRoot - -
    • - -
    • - Line number: 7180 -
    • -
    - -
    - -

    Impact

    -

    Container could be running with full administrative privileges

    - -

    Remediation

    -

    Set `securityContext.runAsNonRoot` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running without root user control

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-10 -
    • - -
    • Introduced through: - [DocId: 39] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - runAsNonRoot - -
    • - -
    • - Line number: 7465 -
    • -
    - -
    - -

    Impact

    -

    Container could be running with full administrative privileges

    - -

    Remediation

    -

    Set `securityContext.runAsNonRoot` to `true`

    - - -
    -
    - - - -
    -
    -

    Role with dangerous permissions

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-47 -
    • - -
    • Introduced through: - [DocId: 7] - - rules[0] - - resources - -
    • - -
    • - Line number: 6565 -
    • -
    - -
    - -

    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[3] - - resources - -
    • - -
    • - Line number: 6637 -
    • -
    - -
    - -

    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: 6665 -
    • -
    - -
    - -

    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: 6709 -
    • -
    - -
    - -

    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: 6691 -
    • -
    - -
    - -

    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: 6725 -
    • -
    - -
    - -

    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: 39] - - spec - - template - - spec - - initContainers[copyutil] - - imagePullPolicy - -
    • - -
    • - Line number: 7465 -
    • -
    - -
    - -

    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: 35] - - input - - spec - - template - - spec - - containers[argocd-applicationset-controller] - - resources - - limits - - cpu - -
    • - -
    • - Line number: 7096 -
    • -
    - -
    - -

    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 - - initContainers[copyutil] - - resources - - limits - - cpu - -
    • - -
    • - Line number: 7180 -
    • -
    - -
    - -

    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[dex] - - resources - - limits - - cpu - -
    • - -
    • - Line number: 7160 -
    • -
    - -
    - -

    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[argocd-notifications-controller] - - resources - - limits - - cpu - -
    • - -
    • - Line number: 7216 -
    • -
    - -
    - -

    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[redis] - - resources - - limits - - cpu - -
    • - -
    • - Line number: 7282 -
    • -
    - -
    - -

    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 - - initContainers[copyutil] - - resources - - limits - - cpu - -
    • - -
    • - Line number: 7465 -
    • -
    - -
    - -

    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-repo-server] - - resources - - limits - - cpu - -
    • - -
    • - Line number: 7331 -
    • -
    - -
    - -

    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-server] - - resources - - limits - - cpu - -
    • - -
    • - Line number: 7540 -
    • -
    - -
    - -

    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: 41] - - input - - spec - - template - - spec - - containers[argocd-application-controller] - - resources - - limits - - cpu - -
    • - -
    • - Line number: 7790 -
    • -
    - -
    - -

    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: 36] - - spec - - template - - spec - - containers[dex] - - ports - -
    • - -
    • - Line number: 7167 -
    • -
    - -
    - -

    Impact

    -

    Increases the attack surface of the application and the container.

    - -

    Remediation

    -

    Reduce `ports` count to 2

    - - -
    -
    - - - -
    -
    -

    Container is running with writable root filesystem

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-8 -
    • - -
    • Introduced through: - [DocId: 35] - - input - - spec - - template - - spec - - containers[argocd-applicationset-controller] - - securityContext - - readOnlyRootFilesystem - -
    • - -
    • - Line number: 7096 -
    • -
    - -
    - -

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    - -

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running with writable root filesystem

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-8 -
    • - -
    • Introduced through: - [DocId: 36] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - readOnlyRootFilesystem - -
    • - -
    • - Line number: 7180 -
    • -
    - -
    - -

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    - -

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running with writable root filesystem

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-8 -
    • - -
    • Introduced through: - [DocId: 37] - - input - - spec - - template - - spec - - containers[argocd-notifications-controller] - - securityContext - - readOnlyRootFilesystem - -
    • - -
    • - Line number: 7216 -
    • -
    - -
    - -

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    - -

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running with writable root filesystem

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-8 -
    • - -
    • Introduced through: - [DocId: 38] - - input - - spec - - template - - spec - - containers[redis] - - securityContext - - readOnlyRootFilesystem - -
    • - -
    • - Line number: 7282 -
    • -
    - -
    - -

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    - -

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running with writable root filesystem

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-8 -
    • - -
    • Introduced through: - [DocId: 39] - - input - - spec - - template - - spec - - initContainers[copyutil] - - securityContext - - readOnlyRootFilesystem - -
    • - -
    • - Line number: 7465 -
    • -
    - -
    - -

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    - -

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    - - -
    -
    - - - -
    -
    -

    Container is running without liveness probe

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Public ID: SNYK-CC-K8S-41 -
    • - -
    • Introduced through: - [DocId: 35] - - spec - - template - - spec - - containers[argocd-applicationset-controller] - - livenessProbe - -
    • - -
    • - Line number: 7096 -
    • -
    - -
    - -

    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: 36] - - spec - - template - - spec - - containers[dex] - - livenessProbe - -
    • - -
    • - Line number: 7160 -
    • -
    - -
    - -

    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: 36] - - spec - - template - - spec - - initContainers[copyutil] - - livenessProbe - -
    • - -
    • - Line number: 7180 -
    • -
    - -
    - -

    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 - - containers[redis] - - livenessProbe - -
    • - -
    • - Line number: 7282 -
    • -
    - -
    - -

    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: 39] - - spec - - template - - spec - - initContainers[copyutil] - - livenessProbe - -
    • - -
    • - Line number: 7465 -
    • -
    - -
    - -

    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: 35] - - input - - spec - - template - - spec - - containers[argocd-applicationset-controller] - - resources - - limits - - memory - -
    • - -
    • - Line number: 7096 -
    • -
    - -
    - -

    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[dex] - - resources - - limits - - memory - -
    • - -
    • - Line number: 7160 -
    • -
    - -
    - -

    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 - - initContainers[copyutil] - - resources - - limits - - memory - -
    • - -
    • - Line number: 7180 -
    • -
    - -
    - -

    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[argocd-notifications-controller] - - resources - - limits - - memory - -
    • - -
    • - Line number: 7216 -
    • -
    - -
    - -

    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[redis] - - resources - - limits - - memory - -
    • - -
    • - Line number: 7282 -
    • -
    - -
    - -

    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 - - initContainers[copyutil] - - resources - - limits - - memory - -
    • - -
    • - Line number: 7465 -
    • -
    - -
    - -

    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-repo-server] - - resources - - limits - - memory - -
    • - -
    • - Line number: 7331 -
    • -
    - -
    - -

    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-server] - - resources - - limits - - memory - -
    • - -
    • - Line number: 7540 -
    • -
    - -
    - -

    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: 41] - - input - - spec - - template - - spec - - containers[argocd-application-controller] - - resources - - limits - - memory - -
    • - -
    • - Line number: 7790 -
    • -
    - -
    - -

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    - -

    Remediation

    -

    Set `resources.limits.memory` value

    - - -
    -
    - - - -
    -
    -
    - -
    - - - diff --git a/docs/snyk/v2.3.13/ghcr.io_dexidp_dex_v2.35.3.html b/docs/snyk/v2.3.13/ghcr.io_dexidp_dex_v2.35.3.html deleted file mode 100644 index 2793c5a1fffc5..0000000000000 --- a/docs/snyk/v2.3.13/ghcr.io_dexidp_dex_v2.35.3.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:23:18 am

    -
    -
    - Scanned the following path: -
      -
    • ghcr.io/dexidp/dex:v2.35.3/dexidp/dex (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    14 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|ghcr.io/dexidp/dex
    Path ghcr.io/dexidp/dex:v2.35.3/dexidp/dex
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.3.13/haproxy_2.0.29-alpine.html b/docs/snyk/v2.3.13/haproxy_2.0.29-alpine.html deleted file mode 100644 index dd8eef8394b4b..0000000000000 --- a/docs/snyk/v2.3.13/haproxy_2.0.29-alpine.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:23:21 am

    -
    -
    - Scanned the following path: -
      -
    • haproxy:2.0.29-alpine (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    17 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|haproxy
    Path haproxy:2.0.29-alpine
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.3.13/quay.io_argoproj_argocd_v2.3.13.html b/docs/snyk/v2.3.13/quay.io_argoproj_argocd_v2.3.13.html deleted file mode 100644 index 528814aa093d0..0000000000000 --- a/docs/snyk/v2.3.13/quay.io_argoproj_argocd_v2.3.13.html +++ /dev/null @@ -1,2649 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:23:59 am

    -
    -
    - Scanned the following path: -
      -
    • quay.io/argoproj/argocd:v2.3.13/argoproj/argocd (deb)
    • -
    -
    - -
    -
    16 known vulnerabilities
    -
    102 vulnerable dependency paths
    -
    162 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|quay.io/argoproj/argocd
    Path quay.io/argoproj/argocd:v2.3.13/argoproj/argocd
    Package Manager deb
    Manifest Dockerfile
    -
    -
    -
    -
    -

    Off-by-one Error

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - systemd/libsystemd0 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.3.13 and systemd/libsystemd0@249.11-0ubuntu3.6 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - apt@2.4.8 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - procps/libprocps8@2:3.3.17-6ubuntu2 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - util-linux@2.37.2-4ubuntu3 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - util-linux/bsdutils@1:2.37.2-4ubuntu3 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - apt@2.4.8 - - apt/libapt-pkg6.0@2.4.8 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - libfido2/libfido2-1@1.10.0-1 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - util-linux@2.37.2-4ubuntu3 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - apt@2.4.8 - - apt/libapt-pkg6.0@2.4.8 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream systemd package.

    -

    An off-by-one Error issue was discovered in Systemd in format_timespan() function of time-util.c. An attacker could supply specific values for time and accuracy that leads to buffer overrun in format_timespan(), leading to a Denial of Service.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 systemd.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - krb5/libk5crypto3 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.3.13 and krb5/libk5crypto3@1.19.2-2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - libssh/libssh-4@0.9.6-2build1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - meta-common-packages@meta - - krb5/libkrb5support0@1.19.2-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream krb5 package.

    -

    PAC parsing in MIT Kerberos 5 (aka krb5) before 1.19.4 and 1.20.x before 1.20.1 has integer overflows that may lead to remote code execution (in KDC, kadmind, or a GSS or Kerberos application server) on 32-bit platforms (which have a resultant heap-based buffer overflow), and cause a denial of service on other platforms. This occurs in krb5_pac_parse in lib/krb5/krb/pac.c. Heimdal before 7.7.1 has "a similar bug."

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 krb5.

    -

    References

    - - -
    - - - -
    -
    -

    CVE-2022-46908

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - sqlite3/libsqlite3-0 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd@v2.3.13, gnupg2/gpg@2.2.27-3ubuntu2.1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - sqlite3/libsqlite3-0@3.37.2-2ubuntu0.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream sqlite3 package.

    -

    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

    - - -
    - - - -
    -
    -

    Uncontrolled Recursion

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - pcre3/libpcre3 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.3.13 and pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - grep@3.7-1build1 - - pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream pcre3 package.

    -

    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.3.13 and patch@2.7.6-7build2 - -
    • -
    - -
    - - -

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream patch package.

    -

    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.3.13 and patch@2.7.6-7build2 - -
    • -
    - -
    - - -

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream patch package.

    -

    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 Locking

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

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssl package.

    -

    If an X.509 certificate contains a malformed policy constraint and policy processing is enabled, then a write lock will be taken twice recursively. On some operating systems (most widely: Windows) this results in a denial of service when the affected process hangs. Policy processing being enabled on a publicly facing server is not considered to be a common setup. Policy processing is enabled by passing the -policy&#39; argument to the command line utilities or by calling either X509_VERIFY_PARAM_add0_policy()' or `X509_VERIFY_PARAM_set1_policies()' functions.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssl.

    -

    References

    - - -
    - - - -
    -
    -

    CVE-2021-41617

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - openssh/openssh-client -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.3.13 and openssh/openssh-client@1:8.9p1-3ubuntu0.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssh package.

    -

    sshd in OpenSSH 6.2 through 8.x before 8.8, when certain non-default configurations are used, allows privilege escalation because supplemental groups are not initialized as expected. Helper programs for AuthorizedKeysCommand and AuthorizedPrincipalsCommand may run with privileges associated with group memberships of the sshd process, if the configuration specifies running the command as a different user.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssh.

    -

    References

    - - -
    - - - -
    -
    -

    Information Exposure

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - openssh/openssh-client -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.3.13 and openssh/openssh-client@1:8.9p1-3ubuntu0.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssh package.

    -

    The client side in OpenSSH 5.7 through 8.4 has an Observable Discrepancy leading to an information leak in the algorithm negotiation. This allows man-in-the-middle attackers to target initial connection attempts (where no host key for the server has been cached by the client). NOTE: some reports state that 8.5 and 8.6 are also affected.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssh.

    -

    References

    - - -
    - - - -
    -
    -

    Out-of-bounds Read

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - ncurses/libtinfo6 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.3.13 and ncurses/libtinfo6@6.3-2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - bash@5.1-6ubuntu1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - ncurses/libncursesw6@6.3-2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - less@590-1build1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - libedit/libedit2@3.1-20210910-1build1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - ncurses/libncurses6@6.3-2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - ncurses/ncurses-bin@6.3-2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - procps@2:3.3.17-6ubuntu2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - util-linux@2.37.2-4ubuntu3 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - gnupg2/gpgconf@2.2.27-3ubuntu2.1 - - readline/libreadline8@8.1.2-1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - pinentry/pinentry-curses@1.1.1-1build2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - ncurses/libncursesw6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - procps@2:3.3.17-6ubuntu2 - - ncurses/libncursesw6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - pinentry/pinentry-curses@1.1.1-1build2 - - ncurses/libncursesw6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - ncurses/libncurses6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - procps@2:3.3.17-6ubuntu2 - - ncurses/libncurses6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - ncurses/ncurses-base@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - ncurses/ncurses-bin@6.3-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream ncurses package.

    -

    ncurses 6.3 before patch 20220416 has an out-of-bounds read and segmentation violation in convert_strings in tinfo/read_entry.c in the terminfo library.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 ncurses.

    -

    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.3.13 and krb5/libk5crypto3@1.19.2-2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - libssh/libssh-4@0.9.6-2build1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - meta-common-packages@meta - - krb5/libkrb5support0@1.19.2-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream krb5 package.

    -

    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

    - - -
    - - - -
    -
    -

    CVE-2022-3219

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - gnupg2/gpgv -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.3.13 and gnupg2/gpgv@2.2.27-3ubuntu2.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gpgv@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - apt@2.4.8 - - gnupg2/gpgv@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpgv@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/dirmngr@2.2.27-3ubuntu2.1 - - gnupg2/gpgconf@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - gnupg2/gpgconf@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - 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.3.13 - - 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.3.13 - - gnupg2/dirmngr@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/dirmngr@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - 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.3.13 - - gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - 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.3.13 - - 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.3.13 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - 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.3.13 - - 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.3.13 - - gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - 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.3.13 - - gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - 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.3.13 - - gnupg2/gpgsm@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpgsm@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    This vulnerability has not been analyzed by NVD yet.

    -

    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.3.13 and glibc/libc-bin@2.35-0ubuntu3.1 - -
    • -
    - -
    - - -

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream glibc package.

    -

    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.3.13, git@1:2.34.1-1ubuntu1.6 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - git@1:2.34.1-1ubuntu1.6 - - git/git-man@1:2.34.1-1ubuntu1.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - git@1:2.34.1-1ubuntu1.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - git-lfs@3.0.2-1 - - git@1:2.34.1-1ubuntu1.6 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream git package.

    -

    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

    - - -
    - - - -
    -
    -

    Improper Input Validation

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - coreutils -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.3.13 and coreutils@8.32-4.1ubuntu1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - coreutils@8.32-4.1ubuntu1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream coreutils package.

    -

    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.3.13 and bash@5.1-6ubuntu1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.3.13 - - bash@5.1-6ubuntu1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream bash package.

    -

    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.3.13/redis_6.2.8-alpine.html b/docs/snyk/v2.3.13/redis_6.2.8-alpine.html deleted file mode 100644 index 43779992e4301..0000000000000 --- a/docs/snyk/v2.3.13/redis_6.2.8-alpine.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:24:04 am

    -
    -
    - Scanned the following path: -
      -
    • redis:6.2.8-alpine (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    18 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|redis
    Path redis:6.2.8-alpine
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.4.19/ghcr.io_dexidp_dex_v2.35.3.html b/docs/snyk/v2.4.19/ghcr.io_dexidp_dex_v2.35.3.html deleted file mode 100644 index a7de0984fc218..0000000000000 --- a/docs/snyk/v2.4.19/ghcr.io_dexidp_dex_v2.35.3.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:21:42 am

    -
    -
    - Scanned the following path: -
      -
    • ghcr.io/dexidp/dex:v2.35.3/dexidp/dex (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    14 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|ghcr.io/dexidp/dex
    Path ghcr.io/dexidp/dex:v2.35.3/dexidp/dex
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.4.19/haproxy_2.0.29-alpine.html b/docs/snyk/v2.4.19/haproxy_2.0.29-alpine.html deleted file mode 100644 index 82f50b8f63a41..0000000000000 --- a/docs/snyk/v2.4.19/haproxy_2.0.29-alpine.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:21:47 am

    -
    -
    - Scanned the following path: -
      -
    • haproxy:2.0.29-alpine (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    17 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|haproxy
    Path haproxy:2.0.29-alpine
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.4.19/quay.io_argoproj_argocd_v2.4.19.html b/docs/snyk/v2.4.19/quay.io_argoproj_argocd_v2.4.19.html deleted file mode 100644 index 5ea597bac98f3..0000000000000 --- a/docs/snyk/v2.4.19/quay.io_argoproj_argocd_v2.4.19.html +++ /dev/null @@ -1,2649 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:22:04 am

    -
    -
    - Scanned the following path: -
      -
    • quay.io/argoproj/argocd:v2.4.19/argoproj/argocd (deb)
    • -
    -
    - -
    -
    16 known vulnerabilities
    -
    102 vulnerable dependency paths
    -
    162 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|quay.io/argoproj/argocd
    Path quay.io/argoproj/argocd:v2.4.19/argoproj/argocd
    Package Manager deb
    Manifest Dockerfile
    -
    -
    -
    -
    -

    Off-by-one Error

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - systemd/libsystemd0 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.4.19 and systemd/libsystemd0@249.11-0ubuntu3.6 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - apt@2.4.8 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - procps/libprocps8@2:3.3.17-6ubuntu2 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - util-linux@2.37.2-4ubuntu3 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - util-linux/bsdutils@1:2.37.2-4ubuntu3 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - apt@2.4.8 - - apt/libapt-pkg6.0@2.4.8 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - libfido2/libfido2-1@1.10.0-1 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - util-linux@2.37.2-4ubuntu3 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - apt@2.4.8 - - apt/libapt-pkg6.0@2.4.8 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream systemd package.

    -

    An off-by-one Error issue was discovered in Systemd in format_timespan() function of time-util.c. An attacker could supply specific values for time and accuracy that leads to buffer overrun in format_timespan(), leading to a Denial of Service.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 systemd.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - krb5/libk5crypto3 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.4.19 and krb5/libk5crypto3@1.19.2-2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - libssh/libssh-4@0.9.6-2build1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - meta-common-packages@meta - - krb5/libkrb5support0@1.19.2-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream krb5 package.

    -

    PAC parsing in MIT Kerberos 5 (aka krb5) before 1.19.4 and 1.20.x before 1.20.1 has integer overflows that may lead to remote code execution (in KDC, kadmind, or a GSS or Kerberos application server) on 32-bit platforms (which have a resultant heap-based buffer overflow), and cause a denial of service on other platforms. This occurs in krb5_pac_parse in lib/krb5/krb/pac.c. Heimdal before 7.7.1 has "a similar bug."

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 krb5.

    -

    References

    - - -
    - - - -
    -
    -

    CVE-2022-46908

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - sqlite3/libsqlite3-0 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd@v2.4.19, gnupg2/gpg@2.2.27-3ubuntu2.1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - sqlite3/libsqlite3-0@3.37.2-2ubuntu0.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream sqlite3 package.

    -

    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

    - - -
    - - - -
    -
    -

    Uncontrolled Recursion

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - pcre3/libpcre3 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.4.19 and pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - grep@3.7-1build1 - - pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream pcre3 package.

    -

    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.4.19 and patch@2.7.6-7build2 - -
    • -
    - -
    - - -

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream patch package.

    -

    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.4.19 and patch@2.7.6-7build2 - -
    • -
    - -
    - - -

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream patch package.

    -

    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 Locking

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

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssl package.

    -

    If an X.509 certificate contains a malformed policy constraint and policy processing is enabled, then a write lock will be taken twice recursively. On some operating systems (most widely: Windows) this results in a denial of service when the affected process hangs. Policy processing being enabled on a publicly facing server is not considered to be a common setup. Policy processing is enabled by passing the -policy&#39; argument to the command line utilities or by calling either X509_VERIFY_PARAM_add0_policy()' or `X509_VERIFY_PARAM_set1_policies()' functions.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssl.

    -

    References

    - - -
    - - - -
    -
    -

    CVE-2021-41617

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - openssh/openssh-client -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.4.19 and openssh/openssh-client@1:8.9p1-3ubuntu0.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssh package.

    -

    sshd in OpenSSH 6.2 through 8.x before 8.8, when certain non-default configurations are used, allows privilege escalation because supplemental groups are not initialized as expected. Helper programs for AuthorizedKeysCommand and AuthorizedPrincipalsCommand may run with privileges associated with group memberships of the sshd process, if the configuration specifies running the command as a different user.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssh.

    -

    References

    - - -
    - - - -
    -
    -

    Information Exposure

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - openssh/openssh-client -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.4.19 and openssh/openssh-client@1:8.9p1-3ubuntu0.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssh package.

    -

    The client side in OpenSSH 5.7 through 8.4 has an Observable Discrepancy leading to an information leak in the algorithm negotiation. This allows man-in-the-middle attackers to target initial connection attempts (where no host key for the server has been cached by the client). NOTE: some reports state that 8.5 and 8.6 are also affected.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssh.

    -

    References

    - - -
    - - - -
    -
    -

    Out-of-bounds Read

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - ncurses/libtinfo6 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.4.19 and ncurses/libtinfo6@6.3-2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - bash@5.1-6ubuntu1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - ncurses/libncursesw6@6.3-2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - less@590-1build1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - libedit/libedit2@3.1-20210910-1build1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - ncurses/libncurses6@6.3-2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - ncurses/ncurses-bin@6.3-2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - procps@2:3.3.17-6ubuntu2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - util-linux@2.37.2-4ubuntu3 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - gnupg2/gpgconf@2.2.27-3ubuntu2.1 - - readline/libreadline8@8.1.2-1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - pinentry/pinentry-curses@1.1.1-1build2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - ncurses/libncursesw6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - procps@2:3.3.17-6ubuntu2 - - ncurses/libncursesw6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - pinentry/pinentry-curses@1.1.1-1build2 - - ncurses/libncursesw6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - ncurses/libncurses6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - procps@2:3.3.17-6ubuntu2 - - ncurses/libncurses6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - ncurses/ncurses-base@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - ncurses/ncurses-bin@6.3-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream ncurses package.

    -

    ncurses 6.3 before patch 20220416 has an out-of-bounds read and segmentation violation in convert_strings in tinfo/read_entry.c in the terminfo library.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 ncurses.

    -

    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.4.19 and krb5/libk5crypto3@1.19.2-2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - libssh/libssh-4@0.9.6-2build1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - meta-common-packages@meta - - krb5/libkrb5support0@1.19.2-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream krb5 package.

    -

    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

    - - -
    - - - -
    -
    -

    CVE-2022-3219

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - gnupg2/gpgv -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.4.19 and gnupg2/gpgv@2.2.27-3ubuntu2.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gpgv@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - apt@2.4.8 - - gnupg2/gpgv@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpgv@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/dirmngr@2.2.27-3ubuntu2.1 - - gnupg2/gpgconf@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - gnupg2/gpgconf@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - 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.4.19 - - 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.4.19 - - gnupg2/dirmngr@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/dirmngr@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - 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.4.19 - - gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - 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.4.19 - - 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.4.19 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - 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.4.19 - - 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.4.19 - - gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - 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.4.19 - - gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - 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.4.19 - - gnupg2/gpgsm@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpgsm@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    This vulnerability has not been analyzed by NVD yet.

    -

    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.4.19 and glibc/libc-bin@2.35-0ubuntu3.1 - -
    • -
    - -
    - - -

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream glibc package.

    -

    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.4.19, git@1:2.34.1-1ubuntu1.6 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - git@1:2.34.1-1ubuntu1.6 - - git/git-man@1:2.34.1-1ubuntu1.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - git@1:2.34.1-1ubuntu1.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - git-lfs@3.0.2-1 - - git@1:2.34.1-1ubuntu1.6 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream git package.

    -

    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

    - - -
    - - - -
    -
    -

    Improper Input Validation

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - coreutils -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.4.19 and coreutils@8.32-4.1ubuntu1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - coreutils@8.32-4.1ubuntu1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream coreutils package.

    -

    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.4.19 and bash@5.1-6ubuntu1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.4.19 - - bash@5.1-6ubuntu1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream bash package.

    -

    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.4.19/redis_7.0.7-alpine.html b/docs/snyk/v2.4.19/redis_7.0.7-alpine.html deleted file mode 100644 index 8d5a799fcb574..0000000000000 --- a/docs/snyk/v2.4.19/redis_7.0.7-alpine.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:22:07 am

    -
    -
    - Scanned the following path: -
      -
    • redis:7.0.7-alpine (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    18 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|redis
    Path redis:7.0.7-alpine
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.5.7/ghcr.io_dexidp_dex_v2.35.3.html b/docs/snyk/v2.5.7/ghcr.io_dexidp_dex_v2.35.3.html deleted file mode 100644 index 1462625622f11..0000000000000 --- a/docs/snyk/v2.5.7/ghcr.io_dexidp_dex_v2.35.3.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:20:03 am

    -
    -
    - Scanned the following path: -
      -
    • ghcr.io/dexidp/dex:v2.35.3/dexidp/dex (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    14 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|ghcr.io/dexidp/dex
    Path ghcr.io/dexidp/dex:v2.35.3/dexidp/dex
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.5.7/haproxy_2.6.2-alpine.html b/docs/snyk/v2.5.7/haproxy_2.6.2-alpine.html deleted file mode 100644 index d05e999b1ab85..0000000000000 --- a/docs/snyk/v2.5.7/haproxy_2.6.2-alpine.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:20:05 am

    -
    -
    - Scanned the following path: -
      -
    • haproxy:2.6.2-alpine (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    17 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|haproxy
    Path haproxy:2.6.2-alpine
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.5.7/quay.io_argoproj_argocd_v2.5.7.html b/docs/snyk/v2.5.7/quay.io_argoproj_argocd_v2.5.7.html deleted file mode 100644 index 8633b3405fe50..0000000000000 --- a/docs/snyk/v2.5.7/quay.io_argoproj_argocd_v2.5.7.html +++ /dev/null @@ -1,2649 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:20:22 am

    -
    -
    - Scanned the following path: -
      -
    • quay.io/argoproj/argocd:v2.5.7/argoproj/argocd (deb)
    • -
    -
    - -
    -
    16 known vulnerabilities
    -
    102 vulnerable dependency paths
    -
    162 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|quay.io/argoproj/argocd
    Path quay.io/argoproj/argocd:v2.5.7/argoproj/argocd
    Package Manager deb
    Manifest Dockerfile
    -
    -
    -
    -
    -

    Off-by-one Error

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - systemd/libsystemd0 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.5.7 and systemd/libsystemd0@249.11-0ubuntu3.6 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - apt@2.4.8 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - procps/libprocps8@2:3.3.17-6ubuntu2 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - util-linux@2.37.2-4ubuntu3 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - util-linux/bsdutils@1:2.37.2-4ubuntu3 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - apt@2.4.8 - - apt/libapt-pkg6.0@2.4.8 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - libfido2/libfido2-1@1.10.0-1 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - util-linux@2.37.2-4ubuntu3 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - apt@2.4.8 - - apt/libapt-pkg6.0@2.4.8 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream systemd package.

    -

    An off-by-one Error issue was discovered in Systemd in format_timespan() function of time-util.c. An attacker could supply specific values for time and accuracy that leads to buffer overrun in format_timespan(), leading to a Denial of Service.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 systemd.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - krb5/libk5crypto3 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.5.7 and krb5/libk5crypto3@1.19.2-2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - libssh/libssh-4@0.9.6-2build1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - meta-common-packages@meta - - krb5/libkrb5support0@1.19.2-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream krb5 package.

    -

    PAC parsing in MIT Kerberos 5 (aka krb5) before 1.19.4 and 1.20.x before 1.20.1 has integer overflows that may lead to remote code execution (in KDC, kadmind, or a GSS or Kerberos application server) on 32-bit platforms (which have a resultant heap-based buffer overflow), and cause a denial of service on other platforms. This occurs in krb5_pac_parse in lib/krb5/krb/pac.c. Heimdal before 7.7.1 has "a similar bug."

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 krb5.

    -

    References

    - - -
    - - - -
    -
    -

    CVE-2022-46908

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - sqlite3/libsqlite3-0 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd@v2.5.7, gnupg2/gpg@2.2.27-3ubuntu2.1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - sqlite3/libsqlite3-0@3.37.2-2ubuntu0.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream sqlite3 package.

    -

    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

    - - -
    - - - -
    -
    -

    Uncontrolled Recursion

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - pcre3/libpcre3 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.5.7 and pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - grep@3.7-1build1 - - pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream pcre3 package.

    -

    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.5.7 and patch@2.7.6-7build2 - -
    • -
    - -
    - - -

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream patch package.

    -

    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.5.7 and patch@2.7.6-7build2 - -
    • -
    - -
    - - -

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream patch package.

    -

    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 Locking

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

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssl package.

    -

    If an X.509 certificate contains a malformed policy constraint and policy processing is enabled, then a write lock will be taken twice recursively. On some operating systems (most widely: Windows) this results in a denial of service when the affected process hangs. Policy processing being enabled on a publicly facing server is not considered to be a common setup. Policy processing is enabled by passing the -policy&#39; argument to the command line utilities or by calling either X509_VERIFY_PARAM_add0_policy()' or `X509_VERIFY_PARAM_set1_policies()' functions.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssl.

    -

    References

    - - -
    - - - -
    -
    -

    CVE-2021-41617

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - openssh/openssh-client -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.5.7 and openssh/openssh-client@1:8.9p1-3ubuntu0.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssh package.

    -

    sshd in OpenSSH 6.2 through 8.x before 8.8, when certain non-default configurations are used, allows privilege escalation because supplemental groups are not initialized as expected. Helper programs for AuthorizedKeysCommand and AuthorizedPrincipalsCommand may run with privileges associated with group memberships of the sshd process, if the configuration specifies running the command as a different user.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssh.

    -

    References

    - - -
    - - - -
    -
    -

    Information Exposure

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - openssh/openssh-client -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.5.7 and openssh/openssh-client@1:8.9p1-3ubuntu0.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssh package.

    -

    The client side in OpenSSH 5.7 through 8.4 has an Observable Discrepancy leading to an information leak in the algorithm negotiation. This allows man-in-the-middle attackers to target initial connection attempts (where no host key for the server has been cached by the client). NOTE: some reports state that 8.5 and 8.6 are also affected.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssh.

    -

    References

    - - -
    - - - -
    -
    -

    Out-of-bounds Read

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - ncurses/libtinfo6 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.5.7 and ncurses/libtinfo6@6.3-2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - bash@5.1-6ubuntu1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - ncurses/libncursesw6@6.3-2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - less@590-1build1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - libedit/libedit2@3.1-20210910-1build1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - ncurses/libncurses6@6.3-2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - ncurses/ncurses-bin@6.3-2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - procps@2:3.3.17-6ubuntu2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - util-linux@2.37.2-4ubuntu3 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - gnupg2/gpgconf@2.2.27-3ubuntu2.1 - - readline/libreadline8@8.1.2-1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - pinentry/pinentry-curses@1.1.1-1build2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - ncurses/libncursesw6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - procps@2:3.3.17-6ubuntu2 - - ncurses/libncursesw6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - pinentry/pinentry-curses@1.1.1-1build2 - - ncurses/libncursesw6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - ncurses/libncurses6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - procps@2:3.3.17-6ubuntu2 - - ncurses/libncurses6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - ncurses/ncurses-base@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - ncurses/ncurses-bin@6.3-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream ncurses package.

    -

    ncurses 6.3 before patch 20220416 has an out-of-bounds read and segmentation violation in convert_strings in tinfo/read_entry.c in the terminfo library.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 ncurses.

    -

    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.5.7 and krb5/libk5crypto3@1.19.2-2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - libssh/libssh-4@0.9.6-2build1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - meta-common-packages@meta - - krb5/libkrb5support0@1.19.2-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream krb5 package.

    -

    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

    - - -
    - - - -
    -
    -

    CVE-2022-3219

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - gnupg2/gpgv -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.5.7 and gnupg2/gpgv@2.2.27-3ubuntu2.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gpgv@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - apt@2.4.8 - - gnupg2/gpgv@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpgv@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/dirmngr@2.2.27-3ubuntu2.1 - - gnupg2/gpgconf@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - gnupg2/gpgconf@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - 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.5.7 - - 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.5.7 - - gnupg2/dirmngr@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/dirmngr@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - 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.5.7 - - gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - 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.5.7 - - 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.5.7 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - 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.5.7 - - 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.5.7 - - gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - 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.5.7 - - gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - 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.5.7 - - gnupg2/gpgsm@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpgsm@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    This vulnerability has not been analyzed by NVD yet.

    -

    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.5.7 and glibc/libc-bin@2.35-0ubuntu3.1 - -
    • -
    - -
    - - -

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream glibc package.

    -

    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.5.7, git@1:2.34.1-1ubuntu1.6 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - git@1:2.34.1-1ubuntu1.6 - - git/git-man@1:2.34.1-1ubuntu1.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - git@1:2.34.1-1ubuntu1.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - git-lfs@3.0.2-1 - - git@1:2.34.1-1ubuntu1.6 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream git package.

    -

    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

    - - -
    - - - -
    -
    -

    Improper Input Validation

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - coreutils -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.5.7 and coreutils@8.32-4.1ubuntu1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - coreutils@8.32-4.1ubuntu1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream coreutils package.

    -

    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.5.7 and bash@5.1-6ubuntu1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.5.7 - - bash@5.1-6ubuntu1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream bash package.

    -

    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.5.7/redis_7.0.7-alpine.html b/docs/snyk/v2.5.7/redis_7.0.7-alpine.html deleted file mode 100644 index c875196a099f9..0000000000000 --- a/docs/snyk/v2.5.7/redis_7.0.7-alpine.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:20:24 am

    -
    -
    - Scanned the following path: -
      -
    • redis:7.0.7-alpine (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    18 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|redis
    Path redis:7.0.7-alpine
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.6.0-rc4/argocd-test.html b/docs/snyk/v2.6.0-rc4/argocd-test.html deleted file mode 100644 index 805621ccfd351..0000000000000 --- a/docs/snyk/v2.6.0-rc4/argocd-test.html +++ /dev/null @@ -1,623 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:17:46 am

    -
    -
    - Scanned the following paths: -
      -
    • /argo-cd/argoproj/argo-cd/v2 (gomodules)
    • /argo-cd (yarn)
    • -
    -
    - -
    -
    1 known vulnerabilities
    -
    1 vulnerable dependency paths
    -
    1730 dependencies
    -
    -
    -
    -
    - -
    -
    -
    -

    Regular Expression Denial of Service (ReDoS)

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: npm -
    • -
    • - Vulnerable module: - - cookiejar -
    • - -
    • Introduced through: - - - argo-cd-ui@1.0.0, superagent@7.1.6 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - argo-cd-ui@1.0.0 - - superagent@7.1.6 - - cookiejar@2.1.3 - - - -
    • -
    - -
    - -
    - -

    Overview

    -

    Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) via the Cookie.parse function, which uses an insecure regular expression.

    -

    PoC

    -
    const { CookieJar } = require("cookiejar");
    -        
    -        const jar = new CookieJar();
    -        
    -        const start = performance.now();
    -        const attack = "a" + "t".repeat(50_000);
    -        jar.setCookie(attack);
    -        console.log(`CookieJar.setCookie(): ${performance.now() - start}`);
    -        
    -

    Details

    -

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.

    -

    The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.

    -

    Let’s take the following regular expression as an example:

    -
    regex = /A(B|C+)+D/
    -        
    -

    This regular expression accomplishes the following:

    -
      -
    • A The string must start with the letter 'A'
    • -
    • (B|C+)+ The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the + matches one or more times). The + at the end of this section states that we can look for one or more matches of this section.
    • -
    • D Finally, we ensure this section of the string ends with a 'D'
    • -
    -

    The expression would match inputs such as ABBD, ABCCCCD, ABCBCCCD and ACCCCCD

    -

    It most cases, it doesn't take very long for a regex engine to find a match:

    -
    $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
    -        0.04s user 0.01s system 95% cpu 0.052 total
    -        
    -        $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
    -        1.79s user 0.02s system 99% cpu 1.812 total
    -        
    -

    The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.

    -

    Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.

    -

    Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:

    -
      -
    1. CCC
    2. -
    3. CC+C
    4. -
    5. C+CC
    6. -
    7. C+C+C.
    8. -
    -

    The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.

    -

    From there, the number of steps the engine must use to validate a string just continues to grow.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StringNumber of C'sNumber of steps
    ACCCX338
    ACCCCX471
    ACCCCCX5136
    ACCCCCCCCCCCCCCX1465,553
    -

    By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.

    -

    Remediation

    -

    Upgrade cookiejar to version 2.1.4 or higher.

    -

    References

    - - -
    - - - -
    -
    -
    -
    - - - diff --git a/docs/snyk/v2.6.0-rc4/ghcr.io_dexidp_dex_v2.35.3.html b/docs/snyk/v2.6.0-rc4/ghcr.io_dexidp_dex_v2.35.3.html deleted file mode 100644 index b67180db9cea3..0000000000000 --- a/docs/snyk/v2.6.0-rc4/ghcr.io_dexidp_dex_v2.35.3.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:17:50 am

    -
    -
    - Scanned the following path: -
      -
    • ghcr.io/dexidp/dex:v2.35.3/dexidp/dex (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    14 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|ghcr.io/dexidp/dex
    Path ghcr.io/dexidp/dex:v2.35.3/dexidp/dex
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.6.0-rc4/haproxy_2.6.2-alpine.html b/docs/snyk/v2.6.0-rc4/haproxy_2.6.2-alpine.html deleted file mode 100644 index 93198b20ea6fe..0000000000000 --- a/docs/snyk/v2.6.0-rc4/haproxy_2.6.2-alpine.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:17:52 am

    -
    -
    - Scanned the following path: -
      -
    • haproxy:2.6.2-alpine (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    17 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|haproxy
    Path haproxy:2.6.2-alpine
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.6.0-rc4/quay.io_argoproj_argocd_v2.6.0-rc4.html b/docs/snyk/v2.6.0-rc4/quay.io_argoproj_argocd_v2.6.0-rc4.html deleted file mode 100644 index 691d2db5efd00..0000000000000 --- a/docs/snyk/v2.6.0-rc4/quay.io_argoproj_argocd_v2.6.0-rc4.html +++ /dev/null @@ -1,2649 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:18:09 am

    -
    -
    - Scanned the following path: -
      -
    • quay.io/argoproj/argocd:v2.6.0-rc4/argoproj/argocd (deb)
    • -
    -
    - -
    -
    16 known vulnerabilities
    -
    102 vulnerable dependency paths
    -
    162 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|quay.io/argoproj/argocd
    Path quay.io/argoproj/argocd:v2.6.0-rc4/argoproj/argocd
    Package Manager deb
    Manifest Dockerfile
    -
    -
    -
    -
    -

    Off-by-one Error

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - systemd/libsystemd0 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 and systemd/libsystemd0@249.11-0ubuntu3.6 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - apt@2.4.8 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - procps/libprocps8@2:3.3.17-6ubuntu2 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - util-linux@2.37.2-4ubuntu3 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - util-linux/bsdutils@1:2.37.2-4ubuntu3 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - apt@2.4.8 - - apt/libapt-pkg6.0@2.4.8 - - systemd/libsystemd0@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - libfido2/libfido2-1@1.10.0-1 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - util-linux@2.37.2-4ubuntu3 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - apt@2.4.8 - - apt/libapt-pkg6.0@2.4.8 - - systemd/libudev1@249.11-0ubuntu3.6 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream systemd package.

    -

    An off-by-one Error issue was discovered in Systemd in format_timespan() function of time-util.c. An attacker could supply specific values for time and accuracy that leads to buffer overrun in format_timespan(), leading to a Denial of Service.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 systemd.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - krb5/libk5crypto3 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 and krb5/libk5crypto3@1.19.2-2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - libssh/libssh-4@0.9.6-2build1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - meta-common-packages@meta - - krb5/libkrb5support0@1.19.2-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream krb5 package.

    -

    PAC parsing in MIT Kerberos 5 (aka krb5) before 1.19.4 and 1.20.x before 1.20.1 has integer overflows that may lead to remote code execution (in KDC, kadmind, or a GSS or Kerberos application server) on 32-bit platforms (which have a resultant heap-based buffer overflow), and cause a denial of service on other platforms. This occurs in krb5_pac_parse in lib/krb5/krb/pac.c. Heimdal before 7.7.1 has "a similar bug."

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 krb5.

    -

    References

    - - -
    - - - -
    -
    -

    CVE-2022-46908

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - sqlite3/libsqlite3-0 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4, gnupg2/gpg@2.2.27-3ubuntu2.1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - sqlite3/libsqlite3-0@3.37.2-2ubuntu0.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream sqlite3 package.

    -

    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

    - - -
    - - - -
    -
    -

    Uncontrolled Recursion

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - pcre3/libpcre3 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 and pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - grep@3.7-1build1 - - pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream pcre3 package.

    -

    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.6.0-rc4 and patch@2.7.6-7build2 - -
    • -
    - -
    - - -

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream patch package.

    -

    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.0-rc4 and patch@2.7.6-7build2 - -
    • -
    - -
    - - -

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream patch package.

    -

    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 Locking

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

    Detailed paths

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

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssl package.

    -

    If an X.509 certificate contains a malformed policy constraint and policy processing is enabled, then a write lock will be taken twice recursively. On some operating systems (most widely: Windows) this results in a denial of service when the affected process hangs. Policy processing being enabled on a publicly facing server is not considered to be a common setup. Policy processing is enabled by passing the -policy&#39; argument to the command line utilities or by calling either X509_VERIFY_PARAM_add0_policy()' or `X509_VERIFY_PARAM_set1_policies()' functions.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssl.

    -

    References

    - - -
    - - - -
    -
    -

    CVE-2021-41617

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - openssh/openssh-client -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 and openssh/openssh-client@1:8.9p1-3ubuntu0.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssh package.

    -

    sshd in OpenSSH 6.2 through 8.x before 8.8, when certain non-default configurations are used, allows privilege escalation because supplemental groups are not initialized as expected. Helper programs for AuthorizedKeysCommand and AuthorizedPrincipalsCommand may run with privileges associated with group memberships of the sshd process, if the configuration specifies running the command as a different user.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssh.

    -

    References

    - - -
    - - - -
    -
    -

    Information Exposure

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - openssh/openssh-client -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 and openssh/openssh-client@1:8.9p1-3ubuntu0.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream openssh package.

    -

    The client side in OpenSSH 5.7 through 8.4 has an Observable Discrepancy leading to an information leak in the algorithm negotiation. This allows man-in-the-middle attackers to target initial connection attempts (where no host key for the server has been cached by the client). NOTE: some reports state that 8.5 and 8.6 are also affected.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssh.

    -

    References

    - - -
    - - - -
    -
    -

    Out-of-bounds Read

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - ncurses/libtinfo6 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 and ncurses/libtinfo6@6.3-2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - bash@5.1-6ubuntu1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - ncurses/libncursesw6@6.3-2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - less@590-1build1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - libedit/libedit2@3.1-20210910-1build1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - ncurses/libncurses6@6.3-2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - ncurses/ncurses-bin@6.3-2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - procps@2:3.3.17-6ubuntu2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - util-linux@2.37.2-4ubuntu3 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - gnupg2/gpgconf@2.2.27-3ubuntu2.1 - - readline/libreadline8@8.1.2-1 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - pinentry/pinentry-curses@1.1.1-1build2 - - ncurses/libtinfo6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - ncurses/libncursesw6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - procps@2:3.3.17-6ubuntu2 - - ncurses/libncursesw6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - pinentry/pinentry-curses@1.1.1-1build2 - - ncurses/libncursesw6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - ncurses/libncurses6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - procps@2:3.3.17-6ubuntu2 - - ncurses/libncurses6@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - ncurses/ncurses-base@6.3-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - ncurses/ncurses-bin@6.3-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream ncurses package.

    -

    ncurses 6.3 before patch 20220416 has an out-of-bounds read and segmentation violation in convert_strings in tinfo/read_entry.c in the terminfo library.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 ncurses.

    -

    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.6.0-rc4 and krb5/libk5crypto3@1.19.2-2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - krb5/libk5crypto3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - krb5/libkrb5-3@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - openssh/openssh-client@1:8.9p1-3ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - git@1:2.34.1-1ubuntu1.6 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.7 - - libssh/libssh-4@0.9.6-2build1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - meta-common-packages@meta - - krb5/libkrb5support0@1.19.2-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream krb5 package.

    -

    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

    - - -
    - - - -
    -
    -

    CVE-2022-3219

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - gnupg2/gpgv -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 and gnupg2/gpgv@2.2.27-3ubuntu2.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gpgv@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - apt@2.4.8 - - gnupg2/gpgv@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpgv@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/dirmngr@2.2.27-3ubuntu2.1 - - gnupg2/gpgconf@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - gnupg2/gpgconf@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - 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.6.0-rc4 - - 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.6.0-rc4 - - gnupg2/dirmngr@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/dirmngr@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - 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.6.0-rc4 - - gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - 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.6.0-rc4 - - 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.6.0-rc4 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - 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.6.0-rc4 - - 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.6.0-rc4 - - gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - 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.6.0-rc4 - - gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - 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.6.0-rc4 - - gnupg2/gpgsm@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - gnupg2/gpgsm@2.2.27-3ubuntu2.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - gnupg2/gnupg@2.2.27-3ubuntu2.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    This vulnerability has not been analyzed by NVD yet.

    -

    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.6.0-rc4 and glibc/libc-bin@2.35-0ubuntu3.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - glibc/libc-bin@2.35-0ubuntu3.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - meta-common-packages@meta - - glibc/libc6@2.35-0ubuntu3.1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream glibc package.

    -

    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.6.0-rc4, git@1:2.34.1-1ubuntu1.6 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - git@1:2.34.1-1ubuntu1.6 - - git/git-man@1:2.34.1-1ubuntu1.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - git@1:2.34.1-1ubuntu1.6 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - git-lfs@3.0.2-1 - - git@1:2.34.1-1ubuntu1.6 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream git package.

    -

    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

    - - -
    - - - -
    -
    -

    Improper Input Validation

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - coreutils -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 and coreutils@8.32-4.1ubuntu1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - coreutils@8.32-4.1ubuntu1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream coreutils package.

    -

    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.6.0-rc4 and bash@5.1-6ubuntu1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.0-rc4 - - bash@5.1-6ubuntu1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream bash package.

    -

    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.6.0-rc4/redis_7.0.7-alpine.html b/docs/snyk/v2.6.0-rc4/redis_7.0.7-alpine.html deleted file mode 100644 index e25016be291ae..0000000000000 --- a/docs/snyk/v2.6.0-rc4/redis_7.0.7-alpine.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - Snyk test report - - - - - - - - - -
    -
    -
    -
    - - - Snyk - Open Source Security - - - - - - - -
    -

    Snyk test report

    - -

    January 22nd 2023, 12:18:12 am

    -
    -
    - Scanned the following path: -
      -
    • redis:7.0.7-alpine (apk)
    • -
    -
    - -
    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    -
    18 dependencies
    -
    -
    -
    -
    -
    - - - - - - - -
    Project docker-image|redis
    Path redis:7.0.7-alpine
    Package Manager apk
    -
    -
    - No known vulnerabilities detected. -
    -
    - - - diff --git a/docs/snyk/v2.5.7/argocd-iac-install.html b/docs/snyk/v2.7.17/argocd-iac-install.html similarity index 72% rename from docs/snyk/v2.5.7/argocd-iac-install.html rename to docs/snyk/v2.7.17/argocd-iac-install.html index b404470870cf4..cfced2ce2b173 100644 --- a/docs/snyk/v2.5.7/argocd-iac-install.html +++ b/docs/snyk/v2.7.17/argocd-iac-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    January 22nd 2023, 12:21:13 am

    +

    March 24th 2024, 12:23:21 am (UTC+00:00)

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

    Snyk test report

    -
    32 total issues
    +
    39 total issues
    @@ -483,7 +483,7 @@

    Snyk test report

    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -494,7 +494,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -507,29 +507,29 @@

      Role with dangerous permissions

    • - Line number: 9318 + Line number: 16324

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -540,7 +540,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -553,29 +553,29 @@

      Role with dangerous permissions

    • - Line number: 9395 + Line number: 16401

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -586,7 +586,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -599,29 +599,29 @@

      Role with dangerous permissions

    • - Line number: 9423 + Line number: 16429

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -632,42 +632,42 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: [DocId: 13] - rules[3] + rules[1] resources
    • - Line number: 9467 + Line number: 16459

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -678,42 +678,42 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: [DocId: 13] - rules[1] + rules[3] resources
    • - Line number: 9449 + Line number: 16477

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -724,7 +724,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -737,24 +737,24 @@

      Role with dangerous permissions

    • - Line number: 9483 + Line number: 16493

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    @@ -770,7 +770,7 @@

    Container could be running with outdated image

    • - Public ID: SNYK-CC-K8S-42 + Public ID: SNYK-CC-K8S-42
    • Introduced through: @@ -789,7 +789,7 @@

      Container could be running with outdated image

    • - Line number: 10420 + Line number: 17537
    @@ -806,7 +806,7 @@

    Remediation

    @@ -822,7 +822,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -847,7 +847,7 @@

      Container has no CPU limit

    • - Line number: 9950 + Line number: 16980
    @@ -864,7 +864,7 @@

    Remediation

    @@ -880,7 +880,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -905,7 +905,7 @@

      Container has no CPU limit

    • - Line number: 10063 + Line number: 17152
    @@ -922,7 +922,7 @@

    Remediation

    @@ -938,7 +938,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -963,7 +963,7 @@

      Container has no CPU limit

    • - Line number: 10029 + Line number: 17118
    @@ -980,7 +980,7 @@

    Remediation

    @@ -996,7 +996,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -1021,7 +1021,7 @@

      Container has no CPU limit

    • - Line number: 10119 + Line number: 17212
    @@ -1038,7 +1038,7 @@

    Remediation

    @@ -1054,7 +1054,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -1079,7 +1079,7 @@

      Container has no CPU limit

    • - Line number: 10193 + Line number: 17293
    @@ -1096,7 +1096,7 @@

    Remediation

    @@ -1112,7 +1112,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -1137,7 +1137,7 @@

      Container has no CPU limit

    • - Line number: 10420 + Line number: 17537
    @@ -1154,7 +1154,7 @@

    Remediation

    @@ -1170,7 +1170,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -1195,7 +1195,7 @@

      Container has no CPU limit

    • - Line number: 10249 + Line number: 17349
    @@ -1212,7 +1212,7 @@

    Remediation

    @@ -1228,7 +1228,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -1253,7 +1253,7 @@

      Container has no CPU limit

    • - Line number: 10505 + Line number: 17622
    @@ -1270,7 +1270,7 @@

    Remediation

    @@ -1286,7 +1286,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -1311,7 +1311,7 @@

      Container has no CPU limit

    • - Line number: 10802 + Line number: 17932
    @@ -1328,7 +1328,7 @@

    Remediation

    @@ -1344,7 +1344,7 @@

    Container is running with multiple open ports

    • - Public ID: SNYK-CC-K8S-36 + Public ID: SNYK-CC-K8S-36
    • Introduced through: @@ -1363,7 +1363,7 @@

      Container is running with multiple open ports

    • - Line number: 10043 + Line number: 17132
    @@ -1380,7 +1380,7 @@

    Remediation

    @@ -1396,14 +1396,12 @@

    Container is running with writable root filesystem

    • - Public ID: SNYK-CC-K8S-8 + Public ID: SNYK-CC-K8S-8
    • Introduced through: [DocId: 45] - input - spec template @@ -1419,7 +1417,7 @@

      Container is running with writable root filesystem

    • - Line number: 10203 + Line number: 17303
    @@ -1429,14 +1427,14 @@

    Impact

    Compromised process could abuse writable root filesystem to elevate privileges

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    +

    Set `spec.{containers, initContainers}.securityContext.readOnlyRootFilesystem` to `true`


    @@ -1452,7 +1450,7 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: @@ -1471,7 +1469,7 @@

      Container is running without liveness probe

    • - Line number: 9950 + Line number: 16980
    @@ -1488,7 +1486,7 @@

    Remediation

    @@ -1504,7 +1502,7 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: @@ -1523,7 +1521,7 @@

      Container is running without liveness probe

    • - Line number: 10029 + Line number: 17118
    @@ -1540,7 +1538,7 @@

    Remediation

    @@ -1556,11 +1554,11 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: - [DocId: 43] + [DocId: 45] spec @@ -1568,14 +1566,14 @@

      Container is running without liveness probe

      spec - initContainers[copyutil] + containers[redis] livenessProbe
    • - Line number: 10063 + Line number: 17293
    @@ -1592,12 +1590,12 @@

    Remediation

    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1608,11 +1606,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 45] + [DocId: 42] + + input spec @@ -1620,36 +1620,40 @@

      Container is running without liveness probe

      spec - containers[redis] + containers[argocd-applicationset-controller] - livenessProbe + resources + + limits + + memory
    • - Line number: 10193 + Line number: 16980

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1660,11 +1664,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 46] + [DocId: 43] + + input spec @@ -1672,31 +1678,35 @@

      Container is running without liveness probe

      spec - initContainers[copyutil] + containers[dex] - livenessProbe + resources + + limits + + memory
    • - Line number: 10420 + Line number: 17118

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    @@ -1712,11 +1722,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 42] + [DocId: 43] input @@ -1726,7 +1736,7 @@

      Container is running without memory limit

      spec - containers[argocd-applicationset-controller] + initContainers[copyutil] resources @@ -1737,7 +1747,7 @@

      Container is running without memory limit

    • - Line number: 9950 + Line number: 17152
    @@ -1754,7 +1764,7 @@

    Remediation

    @@ -1770,11 +1780,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 43] + [DocId: 44] input @@ -1784,7 +1794,7 @@

      Container is running without memory limit

      spec - containers[dex] + containers[argocd-notifications-controller] resources @@ -1795,7 +1805,7 @@

      Container is running without memory limit

    • - Line number: 10029 + Line number: 17212
    @@ -1812,7 +1822,7 @@

    Remediation

    @@ -1828,11 +1838,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 43] + [DocId: 45] input @@ -1842,7 +1852,7 @@

      Container is running without memory limit

      spec - initContainers[copyutil] + containers[redis] resources @@ -1853,7 +1863,7 @@

      Container is running without memory limit

    • - Line number: 10063 + Line number: 17293
    @@ -1870,7 +1880,7 @@

    Remediation

    @@ -1886,11 +1896,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 44] + [DocId: 46] input @@ -1900,7 +1910,7 @@

      Container is running without memory limit

      spec - containers[argocd-notifications-controller] + initContainers[copyutil] resources @@ -1911,7 +1921,7 @@

      Container is running without memory limit

    • - Line number: 10119 + Line number: 17537
    @@ -1928,7 +1938,7 @@

    Remediation

    @@ -1944,11 +1954,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 45] + [DocId: 46] input @@ -1958,7 +1968,7 @@

      Container is running without memory limit

      spec - containers[redis] + containers[argocd-repo-server] resources @@ -1969,7 +1979,7 @@

      Container is running without memory limit

    • - Line number: 10193 + Line number: 17349
    @@ -1986,7 +1996,7 @@

    Remediation

    @@ -2002,11 +2012,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 46] + [DocId: 47] input @@ -2016,7 +2026,7 @@

      Container is running without memory limit

      spec - initContainers[copyutil] + containers[argocd-server] resources @@ -2027,7 +2037,7 @@

      Container is running without memory limit

    • - Line number: 10420 + Line number: 17622
    @@ -2044,7 +2054,7 @@

    Remediation

    @@ -2060,11 +2070,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 46] + [DocId: 48] input @@ -2074,7 +2084,7 @@

      Container is running without memory limit

      spec - containers[argocd-repo-server] + containers[argocd-application-controller] resources @@ -2085,7 +2095,7 @@

      Container is running without memory limit

    • - Line number: 10249 + Line number: 17932
    @@ -2102,12 +2112,12 @@

    Remediation

    -

    Container is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2118,7 +2128,399 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 42] + + input + + spec + + template + + spec + + containers[argocd-applicationset-controller] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 17055 +
    • +
    + +
    + +

    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 + + initContainers[copyutil] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 17160 +
    • +
    + +
    + +

    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[dex] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 17135 +
    • +
    + +
    + +

    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[argocd-notifications-controller] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 17227 +
    • +
    + +
    + +

    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[redis] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 17303 +
    • +
    + +
    + +

    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 + + initContainers[copyutil] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 17544 +
    • +
    + +
    + +

    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-repo-server] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 17510 +
    • +
    + +
    + +

    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: @@ -2134,38 +2536,36 @@

      Container is running without memory limit

      containers[argocd-server] - resources - - limits + securityContext - memory + runAsUser
    • - Line number: 10505 + Line number: 17842

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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 is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2176,7 +2576,7 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: @@ -2192,33 +2592,31 @@

      Container is running without memory limit

      containers[argocd-application-controller] - resources - - limits + securityContext - memory + runAsUser
    • - Line number: 10802 + Line number: 18074

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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.5.7/argocd-iac-namespace-install.html b/docs/snyk/v2.7.17/argocd-iac-namespace-install.html similarity index 72% rename from docs/snyk/v2.5.7/argocd-iac-namespace-install.html rename to docs/snyk/v2.7.17/argocd-iac-namespace-install.html index 472530a63d5da..f9744975422e6 100644 --- a/docs/snyk/v2.5.7/argocd-iac-namespace-install.html +++ b/docs/snyk/v2.7.17/argocd-iac-namespace-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    January 22nd 2023, 12:21:22 am

    +

    March 24th 2024, 12:23:30 am (UTC+00:00)

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

    Snyk test report

    -
    32 total issues
    +
    39 total issues
    @@ -483,7 +483,7 @@

    Snyk test report

    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -494,7 +494,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -514,22 +514,22 @@

      Role with dangerous permissions


      Impact

      -

      Using this role grants dangerous permissions

      +

      Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

      Remediation

      -

      Consider removing this permissions

      +

      Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -540,7 +540,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -560,22 +560,22 @@

      Role with dangerous permissions


      Impact

      -

      Using this role grants dangerous permissions

      +

      Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

      Remediation

      -

      Consider removing this permissions

      +

      Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -586,7 +586,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -606,22 +606,22 @@

      Role with dangerous permissions


      Impact

      -

      Using this role grants dangerous permissions

      +

      Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

      Remediation

      -

      Consider removing this permissions

      +

      Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -632,42 +632,42 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: [DocId: 10] - rules[3] + rules[1] resources
    • - Line number: 226 + Line number: 212

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -678,42 +678,42 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: [DocId: 10] - rules[1] + rules[3] resources
    • - Line number: 208 + Line number: 230

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -724,7 +724,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -737,24 +737,24 @@

      Role with dangerous permissions

    • - Line number: 242 + Line number: 246

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    @@ -770,7 +770,7 @@

    Container could be running with outdated image

    • - Public ID: SNYK-CC-K8S-42 + Public ID: SNYK-CC-K8S-42
    • Introduced through: @@ -789,7 +789,7 @@

      Container could be running with outdated image

    • - Line number: 1086 + Line number: 1197
    @@ -806,7 +806,7 @@

    Remediation

    @@ -822,7 +822,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -847,7 +847,7 @@

      Container has no CPU limit

    • - Line number: 616 + Line number: 640
    @@ -864,7 +864,7 @@

    Remediation

    @@ -880,7 +880,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -905,7 +905,7 @@

      Container has no CPU limit

    • - Line number: 729 + Line number: 812
    @@ -922,7 +922,7 @@

    Remediation

    @@ -938,7 +938,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -963,7 +963,7 @@

      Container has no CPU limit

    • - Line number: 695 + Line number: 778
    @@ -980,7 +980,7 @@

    Remediation

    @@ -996,7 +996,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -1021,7 +1021,7 @@

      Container has no CPU limit

    • - Line number: 785 + Line number: 872
    @@ -1038,7 +1038,7 @@

    Remediation

    @@ -1054,7 +1054,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -1079,7 +1079,7 @@

      Container has no CPU limit

    • - Line number: 859 + Line number: 953
    @@ -1096,7 +1096,7 @@

    Remediation

    @@ -1112,7 +1112,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -1137,7 +1137,7 @@

      Container has no CPU limit

    • - Line number: 1086 + Line number: 1197
    @@ -1154,7 +1154,7 @@

    Remediation

    @@ -1170,7 +1170,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -1195,7 +1195,7 @@

      Container has no CPU limit

    • - Line number: 915 + Line number: 1009
    @@ -1212,7 +1212,7 @@

    Remediation

    @@ -1228,7 +1228,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -1253,7 +1253,7 @@

      Container has no CPU limit

    • - Line number: 1171 + Line number: 1282
    @@ -1270,7 +1270,7 @@

    Remediation

    @@ -1286,7 +1286,7 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: @@ -1311,7 +1311,7 @@

      Container has no CPU limit

    • - Line number: 1468 + Line number: 1592
    @@ -1328,7 +1328,7 @@

    Remediation

    @@ -1344,7 +1344,7 @@

    Container is running with multiple open ports

    • - Public ID: SNYK-CC-K8S-36 + Public ID: SNYK-CC-K8S-36
    • Introduced through: @@ -1363,7 +1363,7 @@

      Container is running with multiple open ports

    • - Line number: 709 + Line number: 792
    @@ -1380,7 +1380,7 @@

    Remediation

    @@ -1396,14 +1396,12 @@

    Container is running with writable root filesystem

    • - Public ID: SNYK-CC-K8S-8 + Public ID: SNYK-CC-K8S-8
    • Introduced through: [DocId: 38] - input - spec template @@ -1419,7 +1417,7 @@

      Container is running with writable root filesystem

    • - Line number: 869 + Line number: 963
    @@ -1429,14 +1427,14 @@

    Impact

    Compromised process could abuse writable root filesystem to elevate privileges

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    +

    Set `spec.{containers, initContainers}.securityContext.readOnlyRootFilesystem` to `true`


    @@ -1452,7 +1450,7 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: @@ -1471,7 +1469,7 @@

      Container is running without liveness probe

    • - Line number: 616 + Line number: 640
    @@ -1488,7 +1486,7 @@

    Remediation

    @@ -1504,7 +1502,7 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: @@ -1523,7 +1521,7 @@

      Container is running without liveness probe

    • - Line number: 695 + Line number: 778
    @@ -1540,7 +1538,7 @@

    Remediation

    @@ -1556,11 +1554,11 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: - [DocId: 36] + [DocId: 38] spec @@ -1568,14 +1566,14 @@

      Container is running without liveness probe

      spec - initContainers[copyutil] + containers[redis] livenessProbe
    • - Line number: 729 + Line number: 953
    @@ -1592,12 +1590,12 @@

    Remediation

    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1608,11 +1606,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 38] + [DocId: 35] + + input spec @@ -1620,36 +1620,40 @@

      Container is running without liveness probe

      spec - containers[redis] + containers[argocd-applicationset-controller] - livenessProbe + resources + + limits + + memory
    • - Line number: 859 + Line number: 640

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1660,11 +1664,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 39] + [DocId: 36] + + input spec @@ -1672,31 +1678,35 @@

      Container is running without liveness probe

      spec - initContainers[copyutil] + containers[dex] - livenessProbe + resources + + limits + + memory
    • - Line number: 1086 + Line number: 778

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    @@ -1712,11 +1722,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 35] + [DocId: 36] input @@ -1726,7 +1736,7 @@

      Container is running without memory limit

      spec - containers[argocd-applicationset-controller] + initContainers[copyutil] resources @@ -1737,7 +1747,7 @@

      Container is running without memory limit

    • - Line number: 616 + Line number: 812
    @@ -1754,7 +1764,7 @@

    Remediation

    @@ -1770,11 +1780,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 36] + [DocId: 37] input @@ -1784,7 +1794,7 @@

      Container is running without memory limit

      spec - containers[dex] + containers[argocd-notifications-controller] resources @@ -1795,7 +1805,7 @@

      Container is running without memory limit

    • - Line number: 695 + Line number: 872
    @@ -1812,7 +1822,7 @@

    Remediation

    @@ -1828,11 +1838,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 36] + [DocId: 38] input @@ -1842,7 +1852,7 @@

      Container is running without memory limit

      spec - initContainers[copyutil] + containers[redis] resources @@ -1853,7 +1863,7 @@

      Container is running without memory limit

    • - Line number: 729 + Line number: 953
    @@ -1870,7 +1880,7 @@

    Remediation

    @@ -1886,11 +1896,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 37] + [DocId: 39] input @@ -1900,7 +1910,7 @@

      Container is running without memory limit

      spec - containers[argocd-notifications-controller] + initContainers[copyutil] resources @@ -1911,7 +1921,7 @@

      Container is running without memory limit

    • - Line number: 785 + Line number: 1197
    @@ -1928,7 +1938,7 @@

    Remediation

    @@ -1944,11 +1954,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 38] + [DocId: 39] input @@ -1958,7 +1968,7 @@

      Container is running without memory limit

      spec - containers[redis] + containers[argocd-repo-server] resources @@ -1969,7 +1979,7 @@

      Container is running without memory limit

    • - Line number: 859 + Line number: 1009
    @@ -1986,7 +1996,7 @@

    Remediation

    @@ -2002,11 +2012,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 39] + [DocId: 40] input @@ -2016,7 +2026,7 @@

      Container is running without memory limit

      spec - initContainers[copyutil] + containers[argocd-server] resources @@ -2027,7 +2037,7 @@

      Container is running without memory limit

    • - Line number: 1086 + Line number: 1282
    @@ -2044,7 +2054,7 @@

    Remediation

    @@ -2060,11 +2070,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 39] + [DocId: 41] input @@ -2074,7 +2084,7 @@

      Container is running without memory limit

      spec - containers[argocd-repo-server] + containers[argocd-application-controller] resources @@ -2085,7 +2095,7 @@

      Container is running without memory limit

    • - Line number: 915 + Line number: 1592
    @@ -2102,12 +2112,12 @@

    Remediation

    -

    Container is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2118,7 +2128,399 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 35] + + input + + spec + + template + + spec + + containers[argocd-applicationset-controller] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 715 +
    • +
    + +
    + +

    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 + + initContainers[copyutil] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 820 +
    • +
    + +
    + +

    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[dex] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 795 +
    • +
    + +
    + +

    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[argocd-notifications-controller] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 887 +
    • +
    + +
    + +

    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[redis] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 963 +
    • +
    + +
    + +

    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 + + initContainers[copyutil] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 1204 +
    • +
    + +
    + +

    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-repo-server] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 1170 +
    • +
    + +
    + +

    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: @@ -2134,38 +2536,36 @@

      Container is running without memory limit

      containers[argocd-server] - resources - - limits + securityContext - memory + runAsUser
    • - Line number: 1171 + Line number: 1502

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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 is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2176,7 +2576,7 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: @@ -2192,33 +2592,31 @@

      Container is running without memory limit

      containers[argocd-application-controller] - resources - - limits + securityContext - memory + runAsUser
    • - Line number: 1468 + Line number: 1734

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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.3.13/argocd-test.html b/docs/snyk/v2.7.17/argocd-test.html similarity index 61% rename from docs/snyk/v2.3.13/argocd-test.html rename to docs/snyk/v2.7.17/argocd-test.html index b1f378aa6e9e7..f130f831d96d1 100644 --- a/docs/snyk/v2.3.13/argocd-test.html +++ b/docs/snyk/v2.7.17/argocd-test.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,19 +456,20 @@

    Snyk test report

    -

    January 22nd 2023, 12:23:14 am

    +

    March 24th 2024, 12:21:51 am (UTC+00:00)

    Scanned the following paths:
      -
    • /argo-cd/argoproj/argo-cd/v2 (gomodules)
    • /argo-cd (yarn)
    • +
    • /argo-cd/argoproj/argo-cd/v2/go.mod (gomodules)
    • +
    • /argo-cd/ui/yarn.lock (yarn)
    -
    12 known vulnerabilities
    -
    113 vulnerable dependency paths
    -
    1467 dependencies
    +
    10 known vulnerabilities
    +
    106 vulnerable dependency paths
    +
    1755 dependencies
    @@ -477,620 +478,32 @@

    Snyk test report

    -

    Prototype Poisoning

    -
    - -
    - high severity -
    - -
    - -
      -
    • - Package Manager: npm -
    • -
    • - Vulnerable module: - - qs -
    • - -
    • Introduced through: - - - argo-cd-ui@1.0.0, superagent@3.8.3 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - argo-cd-ui@1.0.0 - - superagent@3.8.3 - - qs@6.10.1 - - - -
    • -
    • - Introduced through: - argo-cd-ui@1.0.0 - - git-url-parse@11.1.2 - - git-up@4.0.5 - - parse-url@6.0.5 - - parse-path@4.0.3 - - qs@6.10.1 - - - -
    • -
    - -
    - -
    - -

    Overview

    -

    qs is a querystring parser that supports nesting and arrays, with a depth limit.

    -

    Affected versions of this package are vulnerable to Prototype Poisoning which allows attackers to cause a Node process to hang, processing an Array object whose prototype has been replaced by one with an excessive length value.

    -

    Note: In many typical Express use cases, an unauthenticated remote attacker can place the attack payload in the query string of the URL that is used to visit the application, such as a[__proto__]=b&a[__proto__]&a[length]=100000000.

    -

    Details

    -

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

    -

    Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

    -

    One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

    -

    When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

    -

    Two common types of DoS vulnerabilities:

    -
      -
    • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

      -
    • -
    • Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

      -
    • -
    -

    Remediation

    -

    Upgrade qs to version 6.2.4, 6.3.3, 6.4.1, 6.5.3, 6.6.1, 6.7.3, 6.8.3, 6.9.7, 6.10.3 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Regular Expression Denial of Service (ReDoS)

    -
    - -
    - high severity -
    - -
    - -
      -
    • - Package Manager: npm -
    • -
    • - Vulnerable module: - - moment -
    • - -
    • Introduced through: - - - argo-cd-ui@1.0.0, argo-ui@1.0.0 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - argo-cd-ui@1.0.0 - - argo-ui@1.0.0 - - moment@2.29.1 - - - -
    • -
    • - Introduced through: - argo-cd-ui@1.0.0 - - argo-ui@1.0.0 - - antd@4.18.3 - - moment@2.29.1 - - - -
    • -
    • - Introduced through: - argo-cd-ui@1.0.0 - - argo-ui@1.0.0 - - moment-timezone@0.5.33 - - moment@2.29.1 - - - -
    • -
    • - Introduced through: - argo-cd-ui@1.0.0 - - argo-ui@1.0.0 - - antd@4.18.3 - - rc-picker@2.5.19 - - moment@2.29.1 - - - -
    • -
    - -
    - -
    - -

    Overview

    -

    moment is a lightweight JavaScript date library for parsing, validating, manipulating, and formatting dates.

    -

    Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) via the preprocessRFC2822() function in from-string.js, when processing a very long crafted string (over 10k characters).

    -

    PoC:

    -
    moment("(".repeat(500000))
    -        
    -

    Details

    -

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.

    -

    The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.

    -

    Let’s take the following regular expression as an example:

    -
    regex = /A(B|C+)+D/
    -        
    -

    This regular expression accomplishes the following:

    -
      -
    • A The string must start with the letter 'A'
    • -
    • (B|C+)+ The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the + matches one or more times). The + at the end of this section states that we can look for one or more matches of this section.
    • -
    • D Finally, we ensure this section of the string ends with a 'D'
    • -
    -

    The expression would match inputs such as ABBD, ABCCCCD, ABCBCCCD and ACCCCCD

    -

    It most cases, it doesn't take very long for a regex engine to find a match:

    -
    $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
    -        0.04s user 0.01s system 95% cpu 0.052 total
    -        
    -        $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
    -        1.79s user 0.02s system 99% cpu 1.812 total
    -        
    -

    The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.

    -

    Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.

    -

    Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:

    -
      -
    1. CCC
    2. -
    3. CC+C
    4. -
    5. C+CC
    6. -
    7. C+C+C.
    8. -
    -

    The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.

    -

    From there, the number of steps the engine must use to validate a string just continues to grow.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StringNumber of C'sNumber of steps
    ACCCX338
    ACCCCX471
    ACCCCCX5136
    ACCCCCCCCCCCCCCX1465,553
    -

    By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.

    -

    Remediation

    -

    Upgrade moment to version 2.29.4 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Server-side Request Forgery (SSRF)

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: npm -
    • -
    • - Vulnerable module: - - parse-url -
    • - -
    • Introduced through: - - - argo-cd-ui@1.0.0, git-url-parse@11.1.2 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - argo-cd-ui@1.0.0 - - git-url-parse@11.1.2 - - git-up@4.0.5 - - parse-url@6.0.5 - - - -
    • -
    - -
    - -
    - -

    Overview

    -

    parse-url is an An advanced url parser supporting git urls too.

    -

    Affected versions of this package are vulnerable to Server-side Request Forgery (SSRF) due to improper detection of protocol, resource, and pathname fields. Exploiting this vulnerability results in bypassing protocol verification.

    -

    PoC:

    -
    import parseUrl from "parse-url";
    -        import fetch from 'node-fetch';
    -        var parsed=parseUrl("http://nnnn@localhost:808:/?id=xss")
    -        if(parsed.resource=="localhost"){
    -        console.log("internal network access is blocked")
    -        }
    -        else{
    -           const response = await fetch('http://'+parsed.resource+parsed.pathname);
    -                console.log(response)
    -         }
    -        
    -

    Remediation

    -

    Upgrade parse-url to version 8.1.0 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Improper Input Validation

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: npm -
    • -
    • - Vulnerable module: - - parse-url -
    • - -
    • Introduced through: - - - argo-cd-ui@1.0.0, git-url-parse@11.1.2 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - argo-cd-ui@1.0.0 - - git-url-parse@11.1.2 - - git-up@4.0.5 - - parse-url@6.0.5 - - - -
    • -
    - -
    - -
    - -

    Overview

    -

    parse-url is an An advanced url parser supporting git urls too.

    -

    Affected versions of this package are vulnerable to Improper Input Validation due to incorrect parsing of URLs. This allows the attacker to craft a malformed URL which can lead to a phishing attack.

    -
    
    -        const parseUrl = require("parse-url");
    -        const Url = require("url");
    -        
    -        const express = require('express');
    -        const app = express();
    -        
    -        var url = "https://www.google.com:x@fakesite.com:x";
    -        parsed = parseUrl(url);
    -        console.log("[*]`parse-url` output: ")
    -        console.log(parsed);
    -        
    -        parsed2 = Url.parse(url);
    -        console.log("[*]`url` output: ")
    -        console.log(parsed2)
    -        
    -        app.get('/', (req, res) => {
    -            if (parsed.host == "www.google.com") {
    -                res.send("<a href=\'" + parsed2.href + "\'>CLICK ME!</a>")
    -            }
    -        })
    -        
    -        app.listen(8888,"0.0.0.0");
    -        
    -

    Remediation

    -

    Upgrade parse-url to version 8.1.0 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Information Exposure

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: npm -
    • -
    • - Vulnerable module: - - node-fetch -
    • - -
    • Introduced through: - - - argo-cd-ui@1.0.0, argo-ui@1.0.0 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - argo-cd-ui@1.0.0 - - argo-ui@1.0.0 - - portable-fetch@3.0.0 - - node-fetch@1.7.3 - - - -
    • -
    - -
    - -
    - -

    Overview

    -

    node-fetch is a light-weight module that brings window.fetch to node.js

    -

    Affected versions of this package are vulnerable to Information Exposure when fetching a remote url with Cookie, if it get a Location response header, it will follow that url and try to fetch that url with provided cookie. This can lead to forwarding secure headers to 3th party.

    -

    Remediation

    -

    Upgrade node-fetch to version 2.6.7, 3.1.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Denial of Service

    +

    Regular Expression Denial of Service (ReDoS)

    -
    - medium severity +
    + high severity

    • - Package Manager: npm -
    • -
    • - Vulnerable module: - - node-fetch + Manifest file: /argo-cd ui/yarn.lock
    • - -
    • Introduced through: - - - argo-cd-ui@1.0.0, argo-ui@1.0.0 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - argo-cd-ui@1.0.0 - - argo-ui@1.0.0 - - portable-fetch@3.0.0 - - node-fetch@1.7.3 - - - -
    • -
    - -
    - -
    - -

    Overview

    -

    node-fetch is a light-weight module that brings window.fetch to node.js

    -

    Affected versions of this package are vulnerable to Denial of Service. Node Fetch did not honor the size option after following a redirect, which means that when a content size was over the limit, a FetchError would never get thrown and the process would end without failure.

    -

    Remediation

    -

    Upgrade node-fetch to version 2.6.1, 3.0.0-beta.9 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Regular Expression Denial of Service (ReDoS)

    -
    - -
    - medium severity -
    - -
    - -
    • Package Manager: npm
    • Vulnerable module: - minimatch + semver
    • Introduced through: - argo-cd-ui@1.0.0 and minimatch@3.0.4 + argo-cd-ui@1.0.0, superagent@8.0.9 and others
    @@ -1104,20 +517,9 @@

    Detailed paths

    Introduced through: argo-cd-ui@1.0.0 - minimatch@3.0.4 - - - - -
  • - Introduced through: - argo-cd-ui@1.0.0 - - redoc@2.0.0-rc.64 + superagent@8.0.9 - @redocly/openapi-core@1.0.0-beta.82 - - minimatch@3.0.4 + semver@7.3.8 @@ -1129,8 +531,26 @@

    Detailed paths


    Overview

    -

    minimatch is a minimal matching utility.

    -

    Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) via the braceExpand function in minimatch.js.

    +

    semver is a semantic version parser used by npm.

    +

    Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) via the function new Range, when untrusted user data is provided as a range.

    +

    PoC

    +
    
    +        const semver = require('semver')
    +        const lengths_2 = [2000, 4000, 8000, 16000, 32000, 64000, 128000]
    +        
    +        console.log("n[+] Valid range - Test payloads")
    +        for (let i = 0; i =1.2.3' + ' '.repeat(lengths_2[i]) + '<1.3.0';
    +        const start = Date.now()
    +        semver.validRange(value)
    +        // semver.minVersion(value)
    +        // semver.maxSatisfying(["1.2.3"], value)
    +        // semver.minSatisfying(["1.2.3"], value)
    +        // new semver.Range(value, {})
    +        
    +        const end = Date.now();
    +        console.log('length=%d, time=%d ms', value.length, end - start);
    +        }
    +        

    Details

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.

    The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.

    @@ -1193,21 +613,27 @@

    Details

    By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.

    Remediation

    -

    Upgrade minimatch to version 3.0.5 or higher.

    +

    Upgrade semver to version 5.7.2, 6.3.1, 7.5.2 or higher.

    References


  • -

    Denial of Service (DoS)

    +

    Infinite loop

    @@ -1217,19 +643,22 @@

    Denial of Service (DoS)


      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • Package Manager: golang
    • Vulnerable module: - golang.org/x/net/http2 + google.golang.org/protobuf/internal/encoding/json
    • Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0, k8s.io/client-go/rest@0.23.1 and others + github.com/argoproj/argo-cd/v2@0.0.0, github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 and others
    @@ -1243,20 +672,13 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - golang.org/x/net/http2@#491a49abca63 - - - - -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + github.com/golang/protobuf/jsonpb@1.4.2 - github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1265,20 +687,15 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/argoproj/pkg/grpc/http@#a4dd357b057e - golang.org/x/net/http2@#491a49abca63 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - github.com/soheilhy/cmux@0.1.5 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1287,11 +704,15 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/cache@0.23.1 + google.golang.org/grpc@1.58.3 + + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1300,24 +721,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/discovery@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.58.3 - golang.org/x/net/http2@#491a49abca63 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/dynamic@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1326,24 +740,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/transport/spdy@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.3.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.58.3 - golang.org/x/net/http2@#491a49abca63 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + google.golang.org/grpc/internal/transport@1.58.3 - github.com/argoproj/pkg/kubeclientmetrics@#36c59d8fafe0 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1352,24 +759,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/testing@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.3.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.58.3 - golang.org/x/net/http2@#491a49abca63 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/kubernetes@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1378,11 +778,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/azure@0.23.1 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 + + google.golang.org/grpc@1.58.3 + + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1391,11 +797,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/gcp@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 + + google.golang.org/grpc@1.58.3 + + google.golang.org/grpc/internal/transport@1.58.3 + + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1404,11 +816,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/oidc@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/grpc/internal/transport@1.58.3 + + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1417,11 +835,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/watch@0.23.1 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.31.0 + + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1430,11 +854,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - google.golang.org/grpc@1.15.0 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 + + google.golang.org/grpc@1.58.3 - google.golang.org/grpc/internal/transport@1.15.0 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1443,13 +873,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + + google.golang.org/grpc@1.58.3 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1458,13 +892,19 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/listers/core/v1@0.23.1 + google.golang.org/grpc/reflection@1.58.3 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.58.3 + + google.golang.org/grpc@1.58.3 + + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/tools/cache@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1473,13 +913,19 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/api@#91deed20b998 + google.golang.org/grpc/health@1.58.3 - k8s.io/client-go/tools/cache@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/grpc/internal/transport@1.58.3 + + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1488,28 +934,98 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/informers/core/v1@0.23.1 + 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.58.3 + + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/tools/cache@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/internal/encoding/json@1.31.0 -
  • + + + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/internal/encoding/json to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Stack-based Buffer Overflow

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
    • Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/informers@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/client-go/tools/cache@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1518,13 +1034,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/clientcmd@0.23.1 + github.com/argoproj/pkg/grpc/http@#a4dd357b057e - k8s.io/client-go/tools/auth@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/client-go/rest@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1533,13 +1049,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/controller@#91deed20b998 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/tools/cache@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1548,13 +1064,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/discovery/fake@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 - k8s.io/client-go/testing@0.23.1 + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.7.0 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1563,13 +1079,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/kubernetes/fake@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.58.3 - k8s.io/client-go/testing@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1578,13 +1096,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/remotecommand@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.3.0 + + google.golang.org/grpc@1.58.3 - k8s.io/client-go/transport/spdy@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1593,13 +1113,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.3.0 + + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1608,13 +1130,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 + + google.golang.org/grpc@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1623,13 +1147,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 - google.golang.org/grpc@1.15.0 + google.golang.org/grpc@1.58.3 - google.golang.org/grpc/internal/transport@1.15.0 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1638,13 +1164,15 @@

      Detailed paths

      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/health/grpc_health_v1@1.58.3 - google.golang.org/grpc@1.15.0 + google.golang.org/grpc@1.58.3 - google.golang.org/grpc/internal/transport@1.15.0 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1653,13 +1181,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.31.0 - google.golang.org/grpc@1.15.0 + google.golang.org/grpc@1.58.3 - google.golang.org/grpc/internal/transport@1.15.0 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1668,13 +1198,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - google.golang.org/grpc/health/grpc_health_v1@1.15.0 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 + + google.golang.org/grpc@1.58.3 - google.golang.org/grpc@1.15.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc/internal/transport@1.15.0 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1683,13 +1215,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/grpc-ecosystem/go-grpc-middleware/auth@1.3.0 + github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + + google.golang.org/grpc@1.58.3 - google.golang.org/grpc@1.15.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc/internal/transport@1.15.0 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1698,13 +1232,15 @@

      Detailed paths

      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.58.3 + + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc@1.15.0 + google.golang.org/grpc/internal/pretty@1.58.3 - google.golang.org/grpc/internal/transport@1.15.0 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1713,13 +1249,17 @@

      Detailed paths

      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/reflection@1.58.3 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.58.3 - google.golang.org/grpc@1.15.0 + google.golang.org/grpc@1.58.3 - google.golang.org/grpc/internal/transport@1.15.0 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1728,15 +1268,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/cache@0.6.2 + google.golang.org/grpc/health@1.58.3 + + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1745,15 +1287,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync@0.6.2 + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.58.3 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1762,15 +1306,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/utils/kube@0.6.2 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.3.0 + + google.golang.org/grpc@1.58.3 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1779,15 +1325,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/cmd@#91deed20b998 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.3.0 + + google.golang.org/grpc@1.58.3 - k8s.io/client-go/tools/clientcmd@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/tools/auth@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1796,15 +1344,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/kubectl/pkg/util/term@0.23.1 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 + + google.golang.org/grpc@1.58.3 - k8s.io/client-go/tools/remotecommand@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/transport/spdy@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1813,15 +1363,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1830,15 +1382,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/api/rbac/v1@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 + + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1847,15 +1401,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1@0.23.1 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.31.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1864,15 +1420,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/api/core/v1@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 + + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1881,15 +1439,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/api/errors@0.23.1 + github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1898,15 +1458,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/reflection@1.58.3 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1915,15 +1479,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/dynamic@0.23.1 + google.golang.org/grpc/health@1.58.3 + + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1932,15 +1500,21 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/transport/spdy@0.23.1 + 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 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1949,32 +1523,95 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/pkg/kubeclientmetrics@#36c59d8fafe0 + 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.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Stack-based Buffer Overflow when processing input that uses pathologically deep nesting.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.32.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
    • Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/testing@0.23.1 - - k8s.io/client-go/rest@0.23.1 - - k8s.io/client-go/transport@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1983,15 +1620,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/kubernetes@0.23.1 + github.com/argoproj/pkg/grpc/http@#a4dd357b057e - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/client-go/transport@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2000,15 +1635,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/azure@0.23.1 - - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2017,15 +1650,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/gcp@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 - k8s.io/client-go/rest@0.23.1 + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 - k8s.io/client-go/transport@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.7.0 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2034,15 +1665,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/oidc@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2051,15 +1682,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - google.golang.org/grpc/health@1.15.0 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.3.0 - google.golang.org/grpc/health/grpc_health_v1@1.15.0 + google.golang.org/grpc@1.58.3 - google.golang.org/grpc@1.15.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc/internal/transport@1.15.0 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2068,15 +1699,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - google.golang.org/grpc/reflection@1.15.0 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.3.0 - google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.15.0 + google.golang.org/grpc@1.58.3 - google.golang.org/grpc@1.15.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc/internal/transport@1.15.0 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2085,17 +1716,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/health@0.6.2 - - github.com/argoproj/gitops-engine/pkg/utils/kube@0.6.2 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2104,17 +1733,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/common@0.6.2 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 - github.com/argoproj/gitops-engine/pkg/utils/kube@0.6.2 + google.golang.org/grpc@1.58.3 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2123,17 +1750,15 @@

      Detailed paths

      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 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/client-go/tools/clientcmd@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/tools/auth@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2142,17 +1767,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.31.0 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2161,17 +1784,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/common@0.6.2 - - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2180,17 +1801,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/hook@0.6.2 - - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2199,17 +1818,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/resource@0.6.2 - - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2218,17 +1835,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/ignore@0.6.2 + google.golang.org/grpc/reflection@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2237,17 +1854,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/syncwaves@0.6.2 + google.golang.org/grpc/health@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2256,17 +1873,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/utils/testing@0.6.2 + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2275,17 +1892,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/cache@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.3.0 - k8s.io/client-go/tools/pager@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2294,17 +1911,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/kubectl/pkg/util/resource@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.3.0 - k8s.io/api/core/v1@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2313,17 +1930,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/health@0.6.2 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 - k8s.io/kubectl/pkg/util/podutils@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2332,17 +1949,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/portforward@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 - k8s.io/api/core/v1@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2351,17 +1968,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/discovery/fake@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/client-go/testing@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2370,17 +1987,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/kubernetes/fake@0.23.1 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.31.0 - k8s.io/client-go/testing@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2389,17 +2006,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/remotecommand@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 - k8s.io/client-go/transport/spdy@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2408,17 +2025,17 @@

      Detailed paths

      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/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a - github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + google.golang.org/grpc@1.58.3 - github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc@1.15.0 + google.golang.org/grpc/internal/pretty@1.58.3 - google.golang.org/grpc/internal/transport@1.15.0 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2427,19 +2044,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/cache@0.6.2 + google.golang.org/grpc/reflection@1.58.3 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.58.3 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2448,19 +2065,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync@0.6.2 + google.golang.org/grpc/health@1.58.3 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2469,19 +2086,21 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/utils/kube@0.6.2 + 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 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 - k8s.io/client-go/discovery@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2490,40 +2109,94 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/runtime/serializer@0.23.1 + 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 - k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#491a49abca63 + google.golang.org/protobuf/encoding/protojson@1.31.0
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Authentication Bypass by Capture-replay

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/crypto/ssh +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@0.0.0 and golang.org/x/crypto/ssh@0.16.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
    • Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/listers/core/v1@0.23.1 - - k8s.io/client-go/tools/cache@0.23.1 - - k8s.io/client-go/tools/pager@0.23.1 - - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 - - k8s.io/apimachinery/pkg/watch@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2532,19 +2205,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/api@#91deed20b998 + golang.org/x/crypto/ssh/knownhosts@0.16.0 - k8s.io/client-go/tools/cache@0.23.1 - - k8s.io/client-go/tools/pager@0.23.1 - - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 - - k8s.io/apimachinery/pkg/watch@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2553,19 +2216,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/informers/core/v1@0.23.1 - - k8s.io/client-go/tools/cache@0.23.1 - - k8s.io/client-go/tools/pager@0.23.1 - - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/watch@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2574,19 +2227,11 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/informers@0.23.1 - - k8s.io/client-go/tools/cache@0.23.1 - - k8s.io/client-go/tools/pager@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/skeema/knownhosts@1.2.1 - k8s.io/apimachinery/pkg/watch@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2595,19 +2240,11 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/controller@#91deed20b998 - - k8s.io/client-go/tools/cache@0.23.1 - - k8s.io/client-go/tools/pager@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/watch@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2616,19 +2253,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/kubectl/pkg/util/term@0.23.1 - - k8s.io/client-go/tools/remotecommand@0.23.1 - - k8s.io/client-go/transport/spdy@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/rest@0.23.1 + github.com/skeema/knownhosts@1.2.1 - k8s.io/client-go/transport@0.23.1 + golang.org/x/crypto/ssh/knownhosts@0.16.0 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2637,21 +2268,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/hook@0.6.2 - - github.com/argoproj/gitops-engine/pkg/sync/hook/helm@0.6.2 - - github.com/argoproj/gitops-engine/pkg/sync/common@0.6.2 - - github.com/argoproj/gitops-engine/pkg/utils/kube@0.6.2 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/discovery@0.23.1 + github.com/skeema/knownhosts@1.2.1 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2660,21 +2283,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/syncwaves@0.6.2 - - github.com/argoproj/gitops-engine/pkg/sync/hook/helm@0.6.2 - - github.com/argoproj/gitops-engine/pkg/sync/common@0.6.2 - - github.com/argoproj/gitops-engine/pkg/utils/kube@0.6.2 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + github.com/xanzy/ssh-agent@0.3.3 - k8s.io/client-go/discovery@0.23.1 + golang.org/x/crypto/ssh/agent@0.16.0 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2683,21 +2298,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/kubernetes/scheme@0.23.1 - - k8s.io/apimachinery/pkg/runtime/serializer@0.23.1 - - k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.23.1 - - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + github.com/go-git/go-git/v5@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/apimachinery/pkg/watch@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2706,21 +2313,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/clientcmd@0.23.1 - - k8s.io/client-go/tools/clientcmd/api/latest@0.23.1 - - k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.23.1 - - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/watch@0.23.1 + github.com/skeema/knownhosts@1.2.1 - k8s.io/apimachinery/pkg/util/net@0.23.1 + golang.org/x/crypto/ssh/knownhosts@0.16.0 - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2729,23 +2330,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/ignore@0.6.2 - - github.com/argoproj/gitops-engine/pkg/sync/hook@0.6.2 - - github.com/argoproj/gitops-engine/pkg/sync/hook/helm@0.6.2 - - github.com/argoproj/gitops-engine/pkg/sync/common@0.6.2 - - github.com/argoproj/gitops-engine/pkg/utils/kube@0.6.2 + github.com/go-git/go-git/v5@5.11.0 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/client-go/discovery@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/rest@0.23.1 + github.com/skeema/knownhosts@1.2.1 - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2754,48 +2347,34 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/diff@0.6.2 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/client-go/kubernetes/scheme@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/runtime/serializer@0.23.1 + github.com/xanzy/ssh-agent@0.3.3 - k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.23.1 + golang.org/x/crypto/ssh/agent@0.16.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 - - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 - - k8s.io/apimachinery/pkg/watch@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.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.23.1 + github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.23.1 + github.com/go-git/go-git/v5@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/watch@0.23.1 + github.com/skeema/knownhosts@1.2.1 - k8s.io/apimachinery/pkg/util/net@0.23.1 + golang.org/x/crypto/ssh/knownhosts@0.16.0 - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2804,23 +2383,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/cmd@#91deed20b998 - - k8s.io/client-go/tools/clientcmd@0.23.1 - - k8s.io/client-go/tools/clientcmd/api/latest@0.23.1 - - k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.23.1 + github.com/go-git/go-git/v5@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/watch@0.23.1 + github.com/xanzy/ssh-agent@0.3.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + golang.org/x/crypto/ssh/agent@0.16.0 - golang.org/x/net/http2@#491a49abca63 + golang.org/x/crypto/ssh@0.16.0 @@ -2832,39 +2405,49 @@

      Detailed paths


      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) due to improper checks and limitations for the number of entries in the cache, which can allow an attacker to consume unbounded amounts of memory by sending a small number of very large keys.

      -

      Details

      -

      Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

      -

      Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

      -

      One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

      -

      When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

      -

      Two common types of DoS vulnerabilities:

      -
        -
      • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

        +

        golang.org/x/crypto/ssh is a SSH client and server

        +

        Affected versions of this package are vulnerable to Authentication Bypass by Capture-replay during the establishment of the secure channel. An attacker can manipulate handshake sequence numbers to delete messages sent immediately after the channel is established.

        +

        Note:

        +
          +
        1. Sequence numbers are only validated once the channel is established and arbitrary messages are allowed during the handshake, allowing them to manipulate the sequence numbers.

        2. -
        3. Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

          +
        4. The potential consequences of the general Terrapin attack are dependent on the messages exchanged after the handshake concludes. If you are using a custom SSH service and do not resort to the authentication protocol, you should check that dropping the first few messages of a connection does not yield security risks.

        5. -
      + +

      Impact:

      +

      While cryptographically novel, there is no discernable impact on the integrity of SSH traffic beyond giving the attacker the ability to delete the message that enables some features related to keystroke timing obfuscation. To successfully carry out the exploitation, the connection needs to be protected using either the ChaCha20-Poly1305 or CBC with Encrypt-then-MAC encryption methods. The attacker must also be able to intercept and modify the connection's traffic.

      +

      Workaround

      +

      Temporarily disable the affected chacha20-poly1305@openssh.com encryption and *-etm@openssh.com MAC algorithms in the affected configuration, and use unaffected algorithms like AES-GCM instead.

      Remediation

      -

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

      +

      Upgrade golang.org/x/crypto/ssh to version 0.17.0 or higher.

      References


    -

    Improper Input Validation

    +

    MPL-2.0 license

    @@ -2874,19 +2457,22 @@

    Improper Input Validation


      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • Package Manager: golang
    • - Vulnerable module: + Module: - go.mongodb.org/mongo-driver/bson/bsonrw + github.com/r3labs/diff
    • Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 and github.com/r3labs/diff@1.1.0 - github.com/argoproj/argo-cd/v2@0.0.0, github.com/go-openapi/runtime/middleware@0.19.4 and others
    @@ -2900,34 +2486,69 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/go-openapi/runtime/middleware@0.19.4 - - github.com/go-openapi/validate@0.19.5 - - github.com/go-openapi/strfmt@0.19.3 - - go.mongodb.org/mongo-driver/bson@1.1.2 - - go.mongodb.org/mongo-driver/bson/bsonrw@1.1.2 + github.com/r3labs/diff@1.1.0 + + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + 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 - github.com/go-openapi/runtime/middleware@0.19.4 - - github.com/go-openapi/validate@0.19.5 - - github.com/go-openapi/strfmt@0.19.3 - - go.mongodb.org/mongo-driver/bson@1.1.2 - - go.mongodb.org/mongo-driver/bson/bsoncodec@1.1.2 + code.gitea.io/sdk/gitea@0.15.1 - go.mongodb.org/mongo-driver/bson/bsonrw@1.1.2 + github.com/hashicorp/go-version@1.2.1 @@ -2938,27 +2559,17 @@

      Detailed paths


      -

      Overview

      -

      go.mongodb.org/mongo-driver/bson/bsonrw is a The MongoDB supported driver for Go.

      -

      Affected versions of this package are vulnerable to Improper Input Validation. Specific cstrings input may not be properly validated in the MongoDB Go Driver when marshalling Go objects into BSON. A malicious user could use a Go object with specific string to potentially inject additional fields into marshalled documents.

      -

      Remediation

      -

      Upgrade go.mongodb.org/mongo-driver/bson/bsonrw to version 1.5.1 or higher.

      -

      References

      - +

      MPL-2.0 license


    -

    Insecure Randomness

    +

    MPL-2.0 license

    @@ -2968,19 +2579,22 @@

    Insecure Randomness


      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • Package Manager: golang
    • - Vulnerable module: + Module: - github.com/Masterminds/goutils + github.com/hashicorp/go-retryablehttp
    • Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 and github.com/hashicorp/go-retryablehttp@0.7.0 - github.com/argoproj/argo-cd/v2@0.0.0, github.com/argoproj/notifications-engine/pkg/api@#91deed20b998 and others
    @@ -2994,13 +2608,61 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/api@#91deed20b998 + github.com/hashicorp/go-retryablehttp@0.7.0 + + + + +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/xanzy/go-gitlab@0.60.0 + + github.com/hashicorp/go-retryablehttp@0.7.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/services@#f754726f03da + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#f754726f03da + + github.com/argoproj/notifications-engine/pkg/services@#f754726f03da + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.0 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#f754726f03da - github.com/argoproj/notifications-engine/pkg/templates@#91deed20b998 + github.com/argoproj/notifications-engine/pkg/services@#f754726f03da - github.com/Masterminds/sprig@2.22.0 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-retryablehttp@0.7.0 @@ -3009,15 +2671,15 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/cmd@#91deed20b998 + github.com/argoproj/notifications-engine/pkg/api@#f754726f03da - github.com/argoproj/notifications-engine/pkg/api@#91deed20b998 + github.com/argoproj/notifications-engine/pkg/subscriptions@#f754726f03da - github.com/argoproj/notifications-engine/pkg/templates@#91deed20b998 + github.com/argoproj/notifications-engine/pkg/services@#f754726f03da - github.com/Masterminds/sprig@2.22.0 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-retryablehttp@0.7.0 @@ -3026,15 +2688,15 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/controller@#91deed20b998 + github.com/argoproj/notifications-engine/pkg/controller@#f754726f03da - github.com/argoproj/notifications-engine/pkg/api@#91deed20b998 + github.com/argoproj/notifications-engine/pkg/subscriptions@#f754726f03da - github.com/argoproj/notifications-engine/pkg/templates@#91deed20b998 + github.com/argoproj/notifications-engine/pkg/services@#f754726f03da - github.com/Masterminds/sprig@2.22.0 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-retryablehttp@0.7.0 @@ -3045,25 +2707,17 @@

    Detailed paths


    -

    Overview

    -

    github.com/masterminds/goutils is a provides users with utility functions to manipulate strings in various ways.

    -

    Affected versions of this package are vulnerable to Insecure Randomness via the RandomAlphaNumeric(int) and CryptoRandomAlphaNumeric(int) functions. Small values of int in the functions above will return a smaller subset of results than they should. For example, RandomAlphaNumeric(1) would always return a digit in the 0-9 range, while RandomAlphaNumeric(4) return around ~7 million of the ~13M possible permutations.

    -

    Remediation

    -

    Upgrade github.com/masterminds/goutils to version 1.1.1 or higher.

    -

    References

    - +

    MPL-2.0 license


  • -

    Insecure Randomness

    +

    MPL-2.0 license

    @@ -3073,19 +2727,22 @@

    Insecure Randomness


      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • Package Manager: golang
    • - Vulnerable module: + Module: - github.com/Masterminds/goutils + github.com/hashicorp/go-cleanhttp
    • Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0, github.com/argoproj/notifications-engine/pkg/api@#91deed20b998 and others + github.com/argoproj/argo-cd/v2@0.0.0, github.com/hashicorp/go-retryablehttp@0.7.0 and others
    @@ -3099,13 +2756,82 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/api@#91deed20b998 + github.com/hashicorp/go-retryablehttp@0.7.0 + + 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.60.0 + + 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.60.0 + + github.com/hashicorp/go-retryablehttp@0.7.0 + + 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@#f754726f03da + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.0 + + 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@#f754726f03da + + github.com/argoproj/notifications-engine/pkg/services@#f754726f03da + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.0 + + 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@#f754726f03da + + github.com/argoproj/notifications-engine/pkg/services@#f754726f03da - github.com/argoproj/notifications-engine/pkg/templates@#91deed20b998 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/sprig@2.22.0 + github.com/hashicorp/go-retryablehttp@0.7.0 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-cleanhttp@0.5.2 @@ -3114,15 +2840,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/cmd@#91deed20b998 + github.com/argoproj/notifications-engine/pkg/api@#f754726f03da - github.com/argoproj/notifications-engine/pkg/api@#91deed20b998 + github.com/argoproj/notifications-engine/pkg/subscriptions@#f754726f03da - github.com/argoproj/notifications-engine/pkg/templates@#91deed20b998 + github.com/argoproj/notifications-engine/pkg/services@#f754726f03da - github.com/Masterminds/sprig@2.22.0 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-retryablehttp@0.7.0 + + github.com/hashicorp/go-cleanhttp@0.5.2 @@ -3131,15 +2859,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/controller@#91deed20b998 + github.com/argoproj/notifications-engine/pkg/controller@#f754726f03da + + github.com/argoproj/notifications-engine/pkg/subscriptions@#f754726f03da - github.com/argoproj/notifications-engine/pkg/api@#91deed20b998 + github.com/argoproj/notifications-engine/pkg/services@#f754726f03da - github.com/argoproj/notifications-engine/pkg/templates@#91deed20b998 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/sprig@2.22.0 + github.com/hashicorp/go-retryablehttp@0.7.0 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-cleanhttp@0.5.2 @@ -3150,25 +2880,17 @@

    Detailed paths


    -

    Overview

    -

    github.com/masterminds/goutils is a provides users with utility functions to manipulate strings in various ways.

    -

    Affected versions of this package are vulnerable to Insecure Randomness when randomly-generated alphanumeric strings contain significantly less entropy than expected, the RandomAlphaNumeric and CryptoRandomAlphaNumeric functions always return strings containing at least one digit from 0 to 9. This significantly reduces the amount of entropy in short strings generated by these functions.

    -

    Remediation

    -

    Upgrade github.com/masterminds/goutils to version 1.1.1 or higher.

    -

    References

    - +

    MPL-2.0 license


  • -

    Regular Expression Denial of Service (ReDoS)

    +

    MPL-2.0 license

    @@ -3179,18 +2901,21 @@

    Regular Expression Denial of Service (ReDoS)

    • - Package Manager: npm + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod
    • - Vulnerable module: + Package Manager: golang +
    • +
    • + Module: - cookiejar + github.com/gosimple/slug
    • Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 and github.com/gosimple/slug@1.13.1 - argo-cd-ui@1.0.0, superagent@3.8.3 and others
    @@ -3202,11 +2927,9 @@

    Detailed paths

    • Introduced through: - argo-cd-ui@1.0.0 - - superagent@3.8.3 + github.com/argoproj/argo-cd/v2@0.0.0 - cookiejar@2.1.2 + github.com/gosimple/slug@1.13.1 @@ -3217,92 +2940,12 @@

      Detailed paths


      -

      Overview

      -

      Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) via the Cookie.parse function, which uses an insecure regular expression.

      -

      PoC

      -
      const { CookieJar } = require("cookiejar");
      -        
      -        const jar = new CookieJar();
      -        
      -        const start = performance.now();
      -        const attack = "a" + "t".repeat(50_000);
      -        jar.setCookie(attack);
      -        console.log(`CookieJar.setCookie(): ${performance.now() - start}`);
      -        
      -

      Details

      -

      Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.

      -

      The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.

      -

      Let’s take the following regular expression as an example:

      -
      regex = /A(B|C+)+D/
      -        
      -

      This regular expression accomplishes the following:

      -
        -
      • A The string must start with the letter 'A'
      • -
      • (B|C+)+ The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the + matches one or more times). The + at the end of this section states that we can look for one or more matches of this section.
      • -
      • D Finally, we ensure this section of the string ends with a 'D'
      • -
      -

      The expression would match inputs such as ABBD, ABCCCCD, ABCBCCCD and ACCCCCD

      -

      It most cases, it doesn't take very long for a regex engine to find a match:

      -
      $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
      -        0.04s user 0.01s system 95% cpu 0.052 total
      -        
      -        $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
      -        1.79s user 0.02s system 99% cpu 1.812 total
      -        
      -

      The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.

      -

      Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.

      -

      Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:

      -
        -
      1. CCC
      2. -
      3. CC+C
      4. -
      5. C+CC
      6. -
      7. C+C+C.
      8. -
      -

      The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.

      -

      From there, the number of steps the engine must use to validate a string just continues to grow.

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      StringNumber of C'sNumber of steps
      ACCCX338
      ACCCCX471
      ACCCCCX5136
      ACCCCCCCCCCCCCCX1465,553
      -

      By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.

      -

      Remediation

      -

      Upgrade cookiejar to version 2.1.4 or higher.

      -

      References

      - +

      MPL-2.0 license


    diff --git a/docs/snyk/v2.7.17/ghcr.io_dexidp_dex_v2.37.0.html b/docs/snyk/v2.7.17/ghcr.io_dexidp_dex_v2.37.0.html new file mode 100644 index 0000000000000..2bc1adb34dcef --- /dev/null +++ b/docs/snyk/v2.7.17/ghcr.io_dexidp_dex_v2.37.0.html @@ -0,0 +1,4337 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    March 24th 2024, 12:21:56 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//usr/local/bin/gomplate (gomodules)
    • +
    • ghcr.io/dexidp/dex:v2.37.0/dexidp/dex//usr/local/bin/docker-entrypoint (gomodules)
    • +
    • ghcr.io/dexidp/dex:v2.37.0/dexidp/dex//usr/local/bin/dex (gomodules)
    • +
    +
    + +
    +
    42 known vulnerabilities
    +
    121 vulnerable dependency paths
    +
    786 dependencies
    +
    +
    +
    +
    + +
    +
    +
    +

    Path Traversal

    +
    + +
    + critical severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-git/go-git/v5 +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/go-git/go-git/v5@v5.4.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/go-git/go-git/v5@v5.4.2 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Path Traversal via malicious server replies. An attacker can create and amend files across the filesystem and potentially achieve remote code execution by sending crafted responses to the client.

    +

    Notes:

    +
      +
    1. This is only exploitable if the client is using ChrootOS, which is the default for certain functions such as PlainClone.

      +
    2. +
    3. Applications using BoundOS or in-memory filesystems are not affected by this issue.

      +
    4. +
    5. Users running versions of go-git from v4 and above are recommended to upgrade to v5.11 in order to mitigate this vulnerability.

      +
    6. +
    +

    Workaround

    +

    This vulnerability can be mitigated by limiting the client's use to trustworthy Git servers.

    +

    Remediation

    +

    Upgrade github.com/go-git/go-git/v5 to version 5.11.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    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

    + + +
    + + + +
    +
    +

    CVE-2023-5363

    +
    + +
    + high 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

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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

    + + +
    + + + +
    +
    +

    Heap-based Buffer Overflow

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/mattn/go-sqlite3 +
    • + +
    • Introduced through: + + github.com/dexidp/dex@* and github.com/mattn/go-sqlite3@v1.14.17 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/mattn/go-sqlite3@v1.14.17 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Heap-based Buffer Overflow via the sessionReadRecord function in the ext/session/sqlite3session.c file. An attacker can cause a program crash or execute arbitrary code by manipulating the input to trigger a heap-based buffer overflow.

    +

    Remediation

    +

    Upgrade github.com/mattn/go-sqlite3 to version 1.14.18 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-jose/go-jose/v3 +
    • + +
    • Introduced through: + + github.com/dexidp/dex@* and github.com/go-jose/go-jose/v3@v3.0.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/go-jose/go-jose/v3@v3.0.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) when decrypting JWE inputs. An attacker can cause a denial-of-service by providing a PBES2 encrypted JWE blob with a very large p2c value.

    +

    Details

    +

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

    +

    Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

    +

    One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

    +

    When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

    +

    Two common types of DoS vulnerabilities:

    +
      +
    • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

      +
    • +
    • Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

      +
    • +
    +

    Remediation

    +

    Upgrade github.com/go-jose/go-jose/v3 to version 3.0.1 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. + 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

    + + +
    + + + +
    +
    +

    Improper Check for Unusual or Exceptional Conditions

    +
    + +
    + 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: Generating excessively long X9.42 DH keys or checking + excessively long X9.42 DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_generate_key() to + generate an X9.42 DH key may experience long delays. Likewise, applications + that use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check() + to check an X9.42 DH key or X9.42 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.

    +

    While DH_check() performs all the necessary checks (as of CVE-2023-3817), + DH_check_pub_key() doesn't make any of these checks, and is therefore + vulnerable for excessively large P and Q parameters.

    +

    Likewise, while DH_generate_key() performs a check for an excessively large + P, it doesn't check for an excessively large Q.

    +

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

    +

    DH_generate_key() and DH_check_pub_key() are also 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_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().

    +

    Also vulnerable are the OpenSSL pkey command line application when using the + "-pubcheck" option, as well as the OpenSSL genpkey command line application.

    +

    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.4-r1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + 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: The POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

    +

    Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

    +

    The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

    +

    The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

    +

    The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-0727

    +
    + +
    + 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: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

    +

    Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

    +

    A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

    +

    OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

    +

    We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

    +

    The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/internal/encoding/json +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/protobuf/internal/encoding/json@v1.28.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/protobuf/internal/encoding/json@v1.28.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/protobuf/internal/encoding/json@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/internal/encoding/json to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Stack-based Buffer Overflow

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/protobuf/encoding/protojson@v1.28.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/protobuf/encoding/protojson@v1.28.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Stack-based Buffer Overflow when processing input that uses pathologically deep nesting.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.32.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/protobuf/encoding/protojson@v1.28.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/protobuf/encoding/protojson@v1.28.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Allocation of Resources Without Limits or Throttling

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 Allocation of Resources Without Limits or Throttling when MaxConcurrentStreams handler goroutines running. A a handler is started until one of the existing handlers exits.

    +

    Note:

    +

    This issue is related to CVE-2023-44487

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    Cross-site Scripting (XSS)

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + 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

    + + +
    + + + +
    +
    +

    Authentication Bypass by Capture-replay

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/crypto/ssh +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and golang.org/x/crypto/ssh@v0.0.0-20220525230936-793ad666bf5e + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + golang.org/x/crypto/ssh@v0.0.0-20220525230936-793ad666bf5e + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/crypto/ssh is a SSH client and server

    +

    Affected versions of this package are vulnerable to Authentication Bypass by Capture-replay during the establishment of the secure channel. An attacker can manipulate handshake sequence numbers to delete messages sent immediately after the channel is established.

    +

    Note:

    +
      +
    1. Sequence numbers are only validated once the channel is established and arbitrary messages are allowed during the handshake, allowing them to manipulate the sequence numbers.

      +
    2. +
    3. The potential consequences of the general Terrapin attack are dependent on the messages exchanged after the handshake concludes. If you are using a custom SSH service and do not resort to the authentication protocol, you should check that dropping the first few messages of a connection does not yield security risks.

      +
    4. +
    +

    Impact:

    +

    While cryptographically novel, there is no discernable impact on the integrity of SSH traffic beyond giving the attacker the ability to delete the message that enables some features related to keystroke timing obfuscation. To successfully carry out the exploitation, the connection needs to be protected using either the ChaCha20-Poly1305 or CBC with Encrypt-then-MAC encryption methods. The attacker must also be able to intercept and modify the connection's traffic.

    +

    Workaround

    +

    Temporarily disable the affected chacha20-poly1305@openssh.com encryption and *-etm@openssh.com MAC algorithms in the affected configuration, and use unaffected algorithms like AES-GCM instead.

    +

    Remediation

    +

    Upgrade golang.org/x/crypto/ssh to version 0.17.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + 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

    + +
    + + + +
    +
    +

    Improper Handling of Highly Compressed Data (Data Amplification)

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-jose/go-jose/v3 +
    • + +
    • Introduced through: + + github.com/dexidp/dex@* and github.com/go-jose/go-jose/v3@v3.0.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/go-jose/go-jose/v3@v3.0.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Improper Handling of Highly Compressed Data (Data Amplification). An attacker could send a JWE containing compressed data that, when decompressed by Decrypt or DecryptMulti, would use large amounts of memory and CPU.

    +

    Remediation

    +

    Upgrade github.com/go-jose/go-jose/v3 to version 3.0.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Uncontrolled Resource Consumption ('Resource Exhaustion')

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-git/go-git/v5/plumbing +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/go-git/go-git/v5/plumbing@v5.4.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/go-git/go-git/v5/plumbing@v5.4.2 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    github.com/go-git/go-git/v5/plumbing is a highly extensible git implementation library written in pure Go.

    +

    Affected versions of this package are vulnerable to Uncontrolled Resource Consumption ('Resource Exhaustion') via specially crafted responses from a Git server, which triggers resource exhaustion in clients.

    +

    Note + This is only exploitable if the client is not using the in-memory filesystem supported by the library.

    +

    Workaround

    +

    In cases where a bump to the latest version of go-git is not possible, we recommend limiting its use to only trust-worthy Git servers.

    +

    Details

    +

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

    +

    Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

    +

    One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

    +

    When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

    +

    Two common types of DoS vulnerabilities:

    +
      +
    • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

      +
    • +
    • Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

      +
    • +
    +

    Remediation

    +

    Upgrade github.com/go-git/go-git/v5/plumbing to version 5.11.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-6237

    +
    + +
    + 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

    +

    This vulnerability has not been analyzed by NVD yet.

    +

    Remediation

    +

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

    + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.7.17/haproxy_2.6.14-alpine.html b/docs/snyk/v2.7.17/haproxy_2.6.14-alpine.html new file mode 100644 index 0000000000000..4487d720d3a0c --- /dev/null +++ b/docs/snyk/v2.7.17/haproxy_2.6.14-alpine.html @@ -0,0 +1,1376 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    March 24th 2024, 12:22:00 am (UTC+00:00)

    +
    +
    + Scanned the following path: +
      +
    • haproxy:2.6.14-alpine (apk)
    • +
    +
    + +
    +
    5 known vulnerabilities
    +
    45 vulnerable dependency paths
    +
    18 dependencies
    +
    +
    +
    +
    +
    + + + + + + + +
    Project docker-image|haproxy
    Path haproxy:2.6.14-alpine
    Package Manager apk
    +
    +
    +
    +
    +

    CVE-2023-5363

    +
    + +
    + high 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

    + + +
    + + + +
    +
    +

    Improper Check for Unusual or Exceptional Conditions

    +
    + +
    + medium 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: Generating excessively long X9.42 DH keys or checking + excessively long X9.42 DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_generate_key() to + generate an X9.42 DH key may experience long delays. Likewise, applications + that use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check() + to check an X9.42 DH key or X9.42 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.

    +

    While DH_check() performs all the necessary checks (as of CVE-2023-3817), + DH_check_pub_key() doesn't make any of these checks, and is therefore + vulnerable for excessively large P and Q parameters.

    +

    Likewise, while DH_generate_key() performs a check for an excessively large + P, it doesn't check for an excessively large Q.

    +

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

    +

    DH_generate_key() and DH_check_pub_key() are also 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_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().

    +

    Also vulnerable are the OpenSSL pkey command line application when using the + "-pubcheck" option, as well as the OpenSSL genpkey command line application.

    +

    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.4-r1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + medium 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: The POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

    +

    Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

    +

    The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

    +

    The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

    +

    The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-0727

    +
    + +
    + medium 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: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

    +

    Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

    +

    A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

    +

    OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

    +

    We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

    +

    The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-6237

    +
    + +
    + 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

    +

    This vulnerability has not been analyzed by NVD yet.

    +

    Remediation

    +

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

    + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.3.13/quay.io_argoproj_argocd-applicationset_v0.4.1.html b/docs/snyk/v2.7.17/quay.io_argoproj_argocd_v2.7.17.html similarity index 51% rename from docs/snyk/v2.3.13/quay.io_argoproj_argocd-applicationset_v0.4.1.html rename to docs/snyk/v2.7.17/quay.io_argoproj_argocd_v2.7.17.html index c2fd5b45a92ef..88785b4be1777 100644 --- a/docs/snyk/v2.3.13/quay.io_argoproj_argocd-applicationset_v0.4.1.html +++ b/docs/snyk/v2.7.17/quay.io_argoproj_argocd_v2.7.17.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,37 +456,32 @@

    Snyk test report

    -

    January 22nd 2023, 12:23:34 am

    +

    March 24th 2024, 12:22:17 am (UTC+00:00)

    - Scanned the following path: + Scanned the following paths:
      -
    • quay.io/argoproj/argocd-applicationset:v0.4.1/argoproj/argocd-applicationset (deb)
    • +
    • quay.io/argoproj/argocd:v2.7.17/argoproj/argocd/Dockerfile (deb)
    • +
    • quay.io/argoproj/argocd:v2.7.17/argoproj/argo-cd/v2//usr/local/bin/argocd (gomodules)
    • +
    • quay.io/argoproj/argocd:v2.7.17/kustomize/kustomize/v5//usr/local/bin/kustomize (gomodules)
    • +
    • quay.io/argoproj/argocd:v2.7.17/helm/v3//usr/local/bin/helm (gomodules)
    • +
    • quay.io/argoproj/argocd:v2.7.17/git-lfs/git-lfs//usr/bin/git-lfs (gomodules)
    -
    71 known vulnerabilities
    -
    244 vulnerable dependency paths
    -
    161 dependencies
    +
    46 known vulnerabilities
    +
    224 vulnerable dependency paths
    +
    2070 dependencies
    -
    - - - - - - - -
    Project docker-image|quay.io/argoproj/argocd-applicationset
    Path quay.io/argoproj/argocd-applicationset:v0.4.1/argoproj/argocd-applicationset
    Package Manager deb
    Manifest Dockerfile
    -
    +
    -

    Loop with Unreachable Exit Condition ('Infinite Loop')

    +

    Denial of Service (DoS)

    @@ -497,17 +492,20 @@

    Loop with Unreachable Exit Condition ('Infinite Loo
    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/helm/v3 /usr/local/bin/helm +
    • +
    • + Package Manager: golang
    • Vulnerable module: - openssl/libssl1.1 + golang.org/x/net/http2/hpack
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and openssl/libssl1.1@1.1.1l-1ubuntu1.1 + helm.sh/helm/v3@* and golang.org/x/net/http2/hpack@v0.5.0
    @@ -520,113 +518,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - cyrus-sasl2/libsasl2-modules@2.1.27+dfsg-2.1build1 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - libfido2/libfido2-1@1.6.0-2build1 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - openssh/openssh-client@1:8.4p1-6ubuntu2.1 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - ca-certificates@20210119ubuntu1 - - openssl@1.1.1l-1ubuntu1.1 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 - - libssh/libssh-4@0.9.6-1 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-1ubuntu9 - - pam/libpam-modules@1.3.1-5ubuntu11 - - libnsl/libnsl2@1.3.0-2build1 - - libtirpc/libtirpc3@1.3.2-2 - - krb5/libgssapi-krb5-2@1.18.3-6 - - krb5/libkrb5-3@1.18.3-6 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - openssl@1.1.1l-1ubuntu1.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - ca-certificates@20210119ubuntu1 + helm.sh/helm/v3@* - openssl@1.1.1l-1ubuntu1.1 + golang.org/x/net/http2/hpack@v0.5.0 @@ -637,54 +531,39 @@

      Detailed paths


      -

      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream openssl package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      The BN_mod_sqrt() function, which computes a modular square root, contains a bug that can cause it to loop forever for non-prime moduli. Internally this function is used when parsing certificates that contain elliptic curve public keys in compressed form or explicit elliptic curve parameters with a base point encoded in compressed form. It is possible to trigger the infinite loop by crafting a certificate that has invalid explicit curve parameters. Since certificate parsing happens prior to verification of the certificate signature, any process that parses an externally supplied certificate may thus be subject to a denial of service attack. The infinite loop can also be reached when parsing crafted private keys as they can contain explicit elliptic curve parameters. Thus vulnerable situations include: - TLS clients consuming server certificates - TLS servers consuming client certificates - Hosting providers taking certificates or private keys from customers - Certificate authorities parsing certification requests from subscribers - Anything else which parses ASN.1 elliptic curve parameters Also any other applications that use the BN_mod_sqrt() where the attacker can control the parameter values are vulnerable to this DoS issue. In the OpenSSL 1.0.2 version the public key is not parsed during initial parsing of the certificate which makes it slightly harder to trigger the infinite loop. However any operation which requires the public key from the certificate will trigger the infinite loop. In particular the attacker can use a self-signed certificate to trigger the loop during verification of the certificate signature. This issue affects OpenSSL versions 1.0.2, 1.1.1 and 3.0. It was addressed in the releases of 1.1.1n and 3.0.2 on the 15th March 2022. Fixed in OpenSSL 3.0.2 (Affected 3.0.0,3.0.1). Fixed in OpenSSL 1.1.1n (Affected 1.1.1-1.1.1m). Fixed in OpenSSL 1.0.2zd (Affected 1.0.2-1.0.2zc).

      +

      Overview

      +

      Affected versions of this package are vulnerable to Denial of Service (DoS) such that a maliciously crafted HTTP/2 stream could cause excessive CPU consumption in the HPACK decoder.

      +

      Details

      +

      Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

      +

      Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

      +

      One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

      +

      When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

      +

      Two common types of DoS vulnerabilities:

      +
        +
      • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

        +
      • +
      • Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

        +
      • +

      Remediation

      -

      Upgrade Ubuntu:21.10 openssl to version 1.1.1l-1ubuntu1.2 or higher.

      +

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

      References


    -

    Exposure of Resource to Wrong Sphere

    +

    Denial of Service (DoS)

    @@ -695,18 +574,21 @@

    Exposure of Resource to Wrong Sphere

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/helm/v3 /usr/local/bin/helm +
    • +
    • + Package Manager: golang
    • Vulnerable module: - expat/libexpat1 + golang.org/x/net/http2
    • Introduced through: + helm.sh/helm/v3@* and golang.org/x/net/http2@v0.5.0 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others
    @@ -718,11 +600,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + helm.sh/helm/v3@* - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 + golang.org/x/net/http2@v0.5.0 @@ -733,37 +613,40 @@

      Detailed paths


      -

      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      xmlparse.c in Expat (aka libexpat) before 2.4.5 allows attackers to insert namespace-separator characters into namespace URIs.

      +

      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) such that a maliciously crafted HTTP/2 stream could cause excessive CPU consumption in the HPACK decoder.

      +

      Details

      +

      Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

      +

      Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

      +

      One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

      +

      When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

      +

      Two common types of DoS vulnerabilities:

      +
        +
      • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

        +
      • +
      • Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

        +
      • +

      Remediation

      -

      Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.1 or higher.

      +

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

      References


    -

    Improper Encoding or Escaping of Output

    +

    Denial of Service (DoS)

    @@ -774,18 +657,21 @@

    Improper Encoding or Escaping of Output

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/helm/v3 /usr/local/bin/helm +
    • +
    • + Package Manager: golang
    • Vulnerable module: - expat/libexpat1 + golang.org/x/net/http2
    • Introduced through: + helm.sh/helm/v3@* and golang.org/x/net/http2@v0.5.0 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others
    @@ -797,11 +683,9 @@

    Detailed paths

    -

    SQL Injection

    +

    Directory Traversal

    @@ -852,17 +738,20 @@

    SQL Injection

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/helm/v3 /usr/local/bin/helm +
    • +
    • + Package Manager: golang
    • Vulnerable module: - cyrus-sasl2/libsasl2-modules + github.com/cyphar/filepath-securejoin
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and cyrus-sasl2/libsasl2-modules@2.1.27+dfsg-2.1build1 + helm.sh/helm/v3@* and github.com/cyphar/filepath-securejoin@v0.2.3
    @@ -875,41 +764,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - cyrus-sasl2/libsasl2-modules@2.1.27+dfsg-2.1build1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 - - openldap/libldap-2.5-0@2.5.6+dfsg-1~exp1ubuntu1 - - cyrus-sasl2/libsasl2-2@2.1.27+dfsg-2.1build1 - - cyrus-sasl2/libsasl2-modules-db@2.1.27+dfsg-2.1build1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + helm.sh/helm/v3@* - git@1:2.32.0-1ubuntu1 - - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 - - openldap/libldap-2.5-0@2.5.6+dfsg-1~exp1ubuntu1 - - cyrus-sasl2/libsasl2-2@2.1.27+dfsg-2.1build1 + github.com/cyphar/filepath-securejoin@v0.2.3 @@ -920,36 +777,47 @@

      Detailed paths


      -

      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream cyrus-sasl2 package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      In Cyrus SASL 2.1.17 through 2.1.27 before 2.1.28, plugins/sql.c does not escape the password for a SQL INSERT or UPDATE statement.

      +

      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 Ubuntu:21.10 cyrus-sasl2 to version 2.1.27+dfsg-2.1ubuntu0.1 or higher.

      +

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

      References


    -

    Out-of-bounds Write

    +

    CVE-2020-22916

    @@ -960,18 +828,21 @@

    Out-of-bounds Write

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - zlib/zlib1g + xz-utils/liblzma5
    • Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 and xz-utils/liblzma5@5.2.5-2ubuntu1 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, meta-common-packages@meta and others
    @@ -983,11 +854,9 @@

    Detailed paths

    -

    Improper Input Validation

    +

    CVE-2023-51767

    @@ -1057,18 +904,21 @@

    Improper Input Validation

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - xz-utils/liblzma5 + openssh/openssh-client
    • Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 and openssh/openssh-client@1:8.9p1-3ubuntu0.6 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, meta-common-packages@meta and others
    @@ -1080,11 +930,9 @@

    Detailed paths

    -

    Files or Directories Accessible to External Parties

    +

    Information Exposure

    @@ -1134,17 +980,20 @@

    Files or Directories Accessible to External Parties

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - util-linux/libblkid1 + libgcrypt20
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and util-linux/libblkid1@2.36.1-8ubuntu2 + docker-image|quay.io/argoproj/argocd@v2.7.17 and libgcrypt20@1.9.4-3ubuntu3
    @@ -1157,183 +1006,221 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/libblkid1@2.36.1-8ubuntu2 + libgcrypt20@1.9.4-3ubuntu3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - e2fsprogs@1.46.3-1ubuntu3 + gnupg2/dirmngr@2.2.27-3ubuntu2.1 - util-linux/libblkid1@2.36.1-8ubuntu2 + libgcrypt20@1.9.4-3ubuntu3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/libmount1@2.36.1-8ubuntu2 + gnupg2/gpg@2.2.27-3ubuntu2.1 - util-linux/libblkid1@2.36.1-8ubuntu2 + libgcrypt20@1.9.4-3ubuntu3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/mount@2.36.1-8ubuntu2 + apt@2.4.11 - util-linux/libblkid1@2.36.1-8ubuntu2 + apt/libapt-pkg6.0@2.4.11 + + libgcrypt20@1.9.4-3ubuntu3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/mount@2.36.1-8ubuntu2 + apt@2.4.11 - util-linux@2.36.1-8ubuntu2 + gnupg2/gpgv@2.2.27-3ubuntu2.1 - util-linux/libblkid1@2.36.1-8ubuntu2 + libgcrypt20@1.9.4-3ubuntu3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/libuuid1@2.36.1-8ubuntu2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + gnupg2/gpg@2.2.27-3ubuntu2.1 - e2fsprogs@1.46.3-1ubuntu3 + gnupg2/gpgconf@2.2.27-3ubuntu2.1 - util-linux/libuuid1@2.36.1-8ubuntu2 + libgcrypt20@1.9.4-3ubuntu3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/mount@2.36.1-8ubuntu2 + gnupg2/gnupg@2.2.27-3ubuntu2.1 - util-linux@2.36.1-8ubuntu2 + gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 - util-linux/libuuid1@2.36.1-8ubuntu2 + libgcrypt20@1.9.4-3ubuntu3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux@2.36.1-8ubuntu2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + gnupg2/gnupg@2.2.27-3ubuntu2.1 - util-linux/mount@2.36.1-8ubuntu2 + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - util-linux@2.36.1-8ubuntu2 + libgcrypt20@1.9.4-3ubuntu3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/libmount1@2.36.1-8ubuntu2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + gnupg2/gnupg@2.2.27-3ubuntu2.1 - util-linux/mount@2.36.1-8ubuntu2 + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 - util-linux/libmount1@2.36.1-8ubuntu2 + libgcrypt20@1.9.4-3ubuntu3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/mount@2.36.1-8ubuntu2 + gnupg2/gnupg@2.2.27-3ubuntu2.1 - util-linux@2.36.1-8ubuntu2 + gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 - util-linux/libmount1@2.36.1-8ubuntu2 + libgcrypt20@1.9.4-3ubuntu3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/libsmartcols1@2.36.1-8ubuntu2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + gnupg2/gnupg@2.2.27-3ubuntu2.1 - util-linux/mount@2.36.1-8ubuntu2 + gnupg2/gpgsm@2.2.27-3ubuntu2.1 - util-linux/libsmartcols1@2.36.1-8ubuntu2 + libgcrypt20@1.9.4-3ubuntu3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + apt@2.4.11 - util-linux/mount@2.36.1-8ubuntu2 + apt/libapt-pkg6.0@2.4.11 - util-linux@2.36.1-8ubuntu2 + systemd/libsystemd0@249.11-0ubuntu3.12 - util-linux/libsmartcols1@2.36.1-8ubuntu2 + libgcrypt20@1.9.4-3ubuntu3
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    A timing-based side-channel flaw was found in libgcrypt's RSA implementation. This issue may allow a remote attacker to initiate a Bleichenbacher-style attack, which can lead to the decryption of RSA ciphertexts.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 libgcrypt20.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2022-48624

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + less +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.7.17 and less@590-1ubuntu0.22.04.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/mount@2.36.1-8ubuntu2 + less@590-1ubuntu0.22.04.1 @@ -1345,34 +1232,28 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream util-linux package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      A logic error was found in the libmount library of util-linux in the function that allows an unprivileged user to unmount a FUSE filesystem. This flaw allows a local user on a vulnerable system to unmount other users' filesystems that are either world-writable themselves (like /tmp) or mounted in a world-writable directory. An attacker may use this flaw to cause a denial of service to applications that use the affected filesystems.

      +

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

      +

      close_altfile in filename.c in less before 606 omits shell_quote calls for LESSCLOSE.

      Remediation

      -

      Upgrade Ubuntu:21.10 util-linux to version 2.36.1-8ubuntu2.2 or higher.

      +

      Upgrade Ubuntu:22.04 less to version 590-1ubuntu0.22.04.2 or higher.

      References


    -

    Files or Directories Accessible to External Parties

    +

    CVE-2024-26461

    @@ -1383,17 +1264,20 @@

    Files or Directories Accessible to External Parties

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - util-linux/libblkid1 + krb5/libk5crypto3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and util-linux/libblkid1@2.36.1-8ubuntu2 + docker-image|quay.io/argoproj/argocd@v2.7.17 and krb5/libk5crypto3@1.19.2-2ubuntu0.3
    @@ -1406,183 +1290,159 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/libblkid1@2.36.1-8ubuntu2 + krb5/libk5crypto3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - e2fsprogs@1.46.3-1ubuntu3 + adduser@3.118ubuntu5 - util-linux/libblkid1@2.36.1-8ubuntu2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + shadow/passwd@1:4.8.1-2ubuntu2.1 - util-linux/libmount1@2.36.1-8ubuntu2 + pam/libpam-modules@1.4.0-11ubuntu2.4 - util-linux/libblkid1@2.36.1-8ubuntu2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - util-linux/mount@2.36.1-8ubuntu2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 - util-linux/libblkid1@2.36.1-8ubuntu2 + krb5/libk5crypto3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - util-linux/mount@2.36.1-8ubuntu2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 - util-linux@2.36.1-8ubuntu2 + krb5/libkrb5-3@1.19.2-2ubuntu0.3 - util-linux/libblkid1@2.36.1-8ubuntu2 + krb5/libk5crypto3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/libuuid1@2.36.1-8ubuntu2 + krb5/libkrb5-3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - e2fsprogs@1.46.3-1ubuntu3 + adduser@3.118ubuntu5 - util-linux/libuuid1@2.36.1-8ubuntu2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.4 - util-linux/mount@2.36.1-8ubuntu2 + libnsl/libnsl2@1.3.0-2build2 - util-linux@2.36.1-8ubuntu2 + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - util-linux/libuuid1@2.36.1-8ubuntu2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux@2.36.1-8ubuntu2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/mount@2.36.1-8ubuntu2 + openssh/openssh-client@1:8.9p1-3ubuntu0.6 - util-linux@2.36.1-8ubuntu2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/libmount1@2.36.1-8ubuntu2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + git@1:2.34.1-1ubuntu1.10 - util-linux/mount@2.36.1-8ubuntu2 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - util-linux/libmount1@2.36.1-8ubuntu2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + git@1:2.34.1-1ubuntu1.10 - util-linux/mount@2.36.1-8ubuntu2 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - util-linux@2.36.1-8ubuntu2 + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 - util-linux/libmount1@2.36.1-8ubuntu2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/libsmartcols1@2.36.1-8ubuntu2 + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/mount@2.36.1-8ubuntu2 - - util-linux/libsmartcols1@2.36.1-8ubuntu2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - util-linux/mount@2.36.1-8ubuntu2 - - util-linux@2.36.1-8ubuntu2 - - util-linux/libsmartcols1@2.36.1-8ubuntu2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - util-linux/mount@2.36.1-8ubuntu2 + krb5/libkrb5support0@1.19.2-2ubuntu0.3 @@ -1594,33 +1454,26 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream util-linux package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      A logic error was found in the libmount library of util-linux in the function that allows an unprivileged user to unmount a FUSE filesystem. This flaw allows an unprivileged local attacker to unmount FUSE filesystems that belong to certain other users who have a UID that is a prefix of the UID of the attacker in its string form. An attacker may use this flaw to cause a denial of service to applications that use the affected filesystems.

      +

      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.

      +

      Kerberos 5 (aka krb5) 1.21.2 contains a memory leak vulnerability in /krb5/src/lib/gssapi/krb5/k5sealv3.c.

      Remediation

      -

      Upgrade Ubuntu:21.10 util-linux to version 2.36.1-8ubuntu2.2 or higher.

      +

      There is no fixed version for Ubuntu:22.04 krb5.

      References


    -

    Out-of-bounds Read

    +

    CVE-2024-26462

    @@ -1631,18 +1484,21 @@

    Out-of-bounds Read

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - sqlite3/libsqlite3-0 + krb5/libk5crypto3
    • Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 and krb5/libk5crypto3@1.19.2-2ubuntu0.3 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, gnupg2/gpg@2.2.20-1ubuntu4 and others
    @@ -1654,313 +1510,159 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - gnupg2/gpg@2.2.20-1ubuntu4 - - sqlite3/libsqlite3-0@3.35.5-1 + krb5/libk5crypto3@1.19.2-2ubuntu0.3
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream sqlite3 package.

    -

    An out-of-bounds read was addressed with improved bounds checking. This issue is fixed in iOS 13.5 and iPadOS 13.5, macOS Catalina 10.15.5, tvOS 13.4.5, watchOS 6.2.5, iTunes 12.10.7 for Windows, iCloud for Windows 11.2, iCloud for Windows 7.19. A malicious application may cause a denial of service or potentially disclose memory contents.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:21.10 sqlite3.

    -

    References

    - - -
    - - - -
    -
    -

    Improper Verification of Cryptographic Signature

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - perl/perl-modules-5.32 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git@1:2.32.0-1ubuntu1 + adduser@3.118ubuntu5 - perl@5.32.1-3ubuntu3 + shadow/passwd@1:4.8.1-2ubuntu2.1 - perl/perl-modules-5.32@5.32.1-3ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + pam/libpam-modules@1.4.0-11ubuntu2.4 - git@1:2.32.0-1ubuntu1 + libnsl/libnsl2@1.3.0-2build2 - perl@5.32.1-3ubuntu3 + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - perl/libperl5.32@5.32.1-3ubuntu3 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 - perl/perl-modules-5.32@5.32.1-3ubuntu3 + krb5/libk5crypto3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git@1:2.32.0-1ubuntu1 + adduser@3.118ubuntu5 - perl@5.32.1-3ubuntu3 + shadow/passwd@1:4.8.1-2ubuntu2.1 - perl/libperl5.32@5.32.1-3ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + pam/libpam-modules@1.4.0-11ubuntu2.4 - git@1:2.32.0-1ubuntu1 + libnsl/libnsl2@1.3.0-2build2 - perl@5.32.1-3ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 - meta-common-packages@meta + krb5/libkrb5-3@1.19.2-2ubuntu0.3 - perl/perl-base@5.32.1-3ubuntu3 + krb5/libk5crypto3@1.19.2-2ubuntu0.3
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream perl package.

    -

    CPAN 2.28 allows Signature Verification Bypass.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:21.10 perl.

    -

    References

    - - -
    - - - -
    -
    -

    OS Command Injection

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - openssl/libssl1.1 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and openssl/libssl1.1@1.1.1l-1ubuntu1.1 - -
    • -
    - -
    - - -

    Detailed paths

    - -
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libkrb5-3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 - cyrus-sasl2/libsasl2-modules@2.1.27+dfsg-2.1build1 + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - libfido2/libfido2-1@1.6.0-2build1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - openssh/openssh-client@1:8.4p1-6ubuntu2.1 + openssh/openssh-client@1:8.9p1-3ubuntu0.6 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - ca-certificates@20210119ubuntu1 + git@1:2.34.1-1ubuntu1.10 - openssl@1.1.1l-1ubuntu1.1 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git@1:2.32.0-1ubuntu1 + git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - libssh/libssh-4@0.9.6-1 + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 adduser@3.118ubuntu5 - shadow/passwd@1:4.8.1-1ubuntu9 - - pam/libpam-modules@1.3.1-5ubuntu11 - - libnsl/libnsl2@1.3.0-2build1 + shadow/passwd@1:4.8.1-2ubuntu2.1 - libtirpc/libtirpc3@1.3.2-2 + pam/libpam-modules@1.4.0-11ubuntu2.4 - krb5/libgssapi-krb5-2@1.18.3-6 + libnsl/libnsl2@1.3.0-2build2 - krb5/libkrb5-3@1.18.3-6 + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - openssl@1.1.1l-1ubuntu1.1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - ca-certificates@20210119ubuntu1 - - openssl@1.1.1l-1ubuntu1.1 + krb5/libkrb5support0@1.19.2-2ubuntu0.3 @@ -1972,38 +1674,26 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream openssl package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      The c_rehash script does not properly sanitise shell metacharacters to prevent command injection. This script is distributed by some operating systems in a manner where it is automatically executed. On such operating systems, an attacker could execute arbitrary commands with the privileges of the script. Use of the c_rehash script is considered obsolete and should be replaced by the OpenSSL rehash command line tool. Fixed in OpenSSL 3.0.3 (Affected 3.0.0,3.0.1,3.0.2). Fixed in OpenSSL 1.1.1o (Affected 1.1.1-1.1.1n). Fixed in OpenSSL 1.0.2ze (Affected 1.0.2-1.0.2zd).

      +

      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.

      +

      Kerberos 5 (aka krb5) 1.21.2 contains a memory leak vulnerability in /krb5/src/kdc/ndr.c.

      Remediation

      -

      Upgrade Ubuntu:21.10 openssl to version 1.1.1l-1ubuntu1.3 or higher.

      +

      There is no fixed version for Ubuntu:22.04 krb5.

      References


    -

    OS Command Injection

    +

    CVE-2024-26458

    @@ -2014,17 +1704,20 @@

    OS Command Injection

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - openssl/libssl1.1 + krb5/libk5crypto3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and openssl/libssl1.1@1.1.1l-1ubuntu1.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 and krb5/libk5crypto3@1.19.2-2ubuntu0.3
    @@ -2037,113 +1730,159 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libk5crypto3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 - cyrus-sasl2/libsasl2-modules@2.1.27+dfsg-2.1build1 + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 - libfido2/libfido2-1@1.6.0-2build1 + krb5/libkrb5-3@1.19.2-2ubuntu0.3 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libk5crypto3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - openssh/openssh-client@1:8.4p1-6ubuntu2.1 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libkrb5-3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 - ca-certificates@20210119ubuntu1 + pam/libpam-modules@1.4.0-11ubuntu2.4 - openssl@1.1.1l-1ubuntu1.1 + libnsl/libnsl2@1.3.0-2build2 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git@1:2.32.0-1ubuntu1 - - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 - libssh/libssh-4@0.9.6-1 + openssh/openssh-client@1:8.9p1-3ubuntu0.6 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - adduser@3.118ubuntu5 + docker-image|quay.io/argoproj/argocd@v2.7.17 - shadow/passwd@1:4.8.1-1ubuntu9 + git@1:2.34.1-1ubuntu1.10 - pam/libpam-modules@1.3.1-5ubuntu11 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - libnsl/libnsl2@1.3.0-2build1 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 - libtirpc/libtirpc3@1.3.2-2 + git@1:2.34.1-1ubuntu1.10 - krb5/libgssapi-krb5-2@1.18.3-6 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - krb5/libkrb5-3@1.18.3-6 + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 - openssl@1.1.1l-1ubuntu1.1 + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - ca-certificates@20210119ubuntu1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - openssl@1.1.1l-1ubuntu1.1 + krb5/libkrb5support0@1.19.2-2ubuntu0.3 @@ -2155,34 +1894,26 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream openssl package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      In addition to the c_rehash shell command injection identified in CVE-2022-1292, further circumstances where the c_rehash script does not properly sanitise shell metacharacters to prevent command injection were found by code review. When the CVE-2022-1292 was fixed it was not discovered that there are other places in the script where the file names of certificates being hashed were possibly passed to a command executed through the shell. This script is distributed by some operating systems in a manner where it is automatically executed. On such operating systems, an attacker could execute arbitrary commands with the privileges of the script. Use of the c_rehash script is considered obsolete and should be replaced by the OpenSSL rehash command line tool. Fixed in OpenSSL 3.0.4 (Affected 3.0.0,3.0.1,3.0.2,3.0.3). Fixed in OpenSSL 1.1.1p (Affected 1.1.1-1.1.1o). Fixed in OpenSSL 1.0.2zf (Affected 1.0.2-1.0.2ze).

      +

      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.

      +

      Kerberos 5 (aka krb5) 1.21.2 contains a memory leak in /krb5/src/lib/rpc/pmap_rmt.c.

      Remediation

      -

      Upgrade Ubuntu:21.10 openssl to version 1.1.1l-1ubuntu1.5 or higher.

      +

      There is no fixed version for Ubuntu:22.04 krb5.

      References


    -

    Inadequate Encryption Strength

    +

    Infinite loop

    @@ -2193,17 +1924,20 @@

    Inadequate Encryption Strength

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang
    • Vulnerable module: - openssl/libssl1.1 + google.golang.org/protobuf/internal/encoding/json
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and openssl/libssl1.1@1.1.1l-1ubuntu1.1 + github.com/argoproj/argo-cd/v2@* and google.golang.org/protobuf/internal/encoding/json@v1.31.0
    @@ -2216,113 +1950,148 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + github.com/argoproj/argo-cd/v2@* - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + google.golang.org/protobuf/internal/encoding/json@v1.31.0
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - cyrus-sasl2/libsasl2-modules@2.1.27+dfsg-2.1build1 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 - - +
    - +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/internal/encoding/json to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Stack-based Buffer Overflow

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/protobuf/encoding/protojson@v1.31.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + github.com/argoproj/argo-cd/v2@* - libfido2/libfido2-1@1.6.0-2build1 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 + google.golang.org/protobuf/encoding/protojson@v1.31.0
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - openssh/openssh-client@1:8.4p1-6ubuntu2.1 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 - - +
    - -
  • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - ca-certificates@20210119ubuntu1 - - openssl@1.1.1l-1ubuntu1.1 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 - - +
  • - -
  • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 - - libssh/libssh-4@0.9.6-1 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 - - +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Stack-based Buffer Overflow when processing input that uses pathologically deep nesting.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.32.0 or higher.

    +

    References

    + -
  • -
  • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-1ubuntu9 - - pam/libpam-modules@1.3.1-5ubuntu11 - - libnsl/libnsl2@1.3.0-2build1 - - libtirpc/libtirpc3@1.3.2-2 - - krb5/libgssapi-krb5-2@1.18.3-6 - - krb5/libkrb5-3@1.18.3-6 - - openssl/libssl1.1@1.1.1l-1ubuntu1.1 - - +
    -
  • -
  • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - openssl@1.1.1l-1ubuntu1.1 - - + -
  • +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/protobuf/encoding/protojson@v1.31.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + github.com/argoproj/argo-cd/v2@* - ca-certificates@20210119ubuntu1 - - openssl@1.1.1l-1ubuntu1.1 + google.golang.org/protobuf/encoding/protojson@v1.31.0 @@ -2333,35 +2102,28 @@

      Detailed paths


      -

      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream openssl package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      AES OCB mode for 32-bit x86 platforms using the AES-NI assembly optimised implementation will not encrypt the entirety of the data under some circumstances. This could reveal sixteen bytes of data that was preexisting in the memory that wasn't written. In the special case of "in place" encryption, sixteen bytes of the plaintext would be revealed. Since OpenSSL does not support OCB based cipher suites for TLS and DTLS, they are both unaffected. Fixed in OpenSSL 3.0.5 (Affected 3.0.0-3.0.4). Fixed in OpenSSL 1.1.1q (Affected 1.1.1-1.1.1p).

      +

      Overview

      +

      Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

      +

      Note:

      +

      This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

      Remediation

      -

      Upgrade Ubuntu:21.10 openssl to version 1.1.1l-1ubuntu1.6 or higher.

      +

      Upgrade google.golang.org/protobuf/encoding/protojson to version 1.33.0 or higher.

      References


    -

    SQL Injection

    +

    Allocation of Resources Without Limits or Throttling

    @@ -2372,18 +2134,21 @@

    SQL Injection

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/helm/v3 /usr/local/bin/helm +
    • +
    • + Package Manager: golang
    • Vulnerable module: - openldap/libldap-2.5-0 + golang.org/x/net/http2
    • Introduced through: + helm.sh/helm/v3@* and golang.org/x/net/http2@v0.5.0 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, gnupg2/dirmngr@2.2.20-1ubuntu4 and others
    @@ -2395,33 +2160,81 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/dirmngr@2.2.20-1ubuntu4 + helm.sh/helm/v3@* - openldap/libldap-2.5-0@2.5.6+dfsg-1~exp1ubuntu1 + golang.org/x/net/http2@v0.5.0
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 - - openldap/libldap-2.5-0@2.5.6+dfsg-1~exp1ubuntu1 - - +
    - +
    + +
    + +

    Overview

    +

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

    +

    Affected versions of this package are vulnerable to Allocation of Resources Without Limits or Throttling when MaxConcurrentStreams handler goroutines running. A a handler is started until one of the existing handlers exits.

    +

    Note:

    +

    This issue is related to CVE-2023-44487

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    Authentication Bypass by Capture-replay

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/crypto/ssh +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and golang.org/x/crypto/ssh@v0.16.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + github.com/argoproj/argo-cd/v2@* - openldap/libldap-common@2.5.6+dfsg-1~exp1ubuntu1 + golang.org/x/crypto/ssh@v0.16.0 @@ -2432,30 +2245,50 @@

      Detailed paths


      -

      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream openldap package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      In OpenLDAP 2.x before 2.5.12 and 2.6.x before 2.6.2, a SQL injection vulnerability exists in the experimental back-sql backend to slapd, via a SQL statement within an LDAP query. This can occur during an LDAP search operation when the search filter is processed, due to a lack of proper escaping.

      +

      Overview

      +

      golang.org/x/crypto/ssh is a SSH client and server

      +

      Affected versions of this package are vulnerable to Authentication Bypass by Capture-replay during the establishment of the secure channel. An attacker can manipulate handshake sequence numbers to delete messages sent immediately after the channel is established.

      +

      Note:

      +
        +
      1. Sequence numbers are only validated once the channel is established and arbitrary messages are allowed during the handshake, allowing them to manipulate the sequence numbers.

        +
      2. +
      3. The potential consequences of the general Terrapin attack are dependent on the messages exchanged after the handshake concludes. If you are using a custom SSH service and do not resort to the authentication protocol, you should check that dropping the first few messages of a connection does not yield security risks.

        +
      4. +
      +

      Impact:

      +

      While cryptographically novel, there is no discernable impact on the integrity of SSH traffic beyond giving the attacker the ability to delete the message that enables some features related to keystroke timing obfuscation. To successfully carry out the exploitation, the connection needs to be protected using either the ChaCha20-Poly1305 or CBC with Encrypt-then-MAC encryption methods. The attacker must also be able to intercept and modify the connection's traffic.

      +

      Workaround

      +

      Temporarily disable the affected chacha20-poly1305@openssh.com encryption and *-etm@openssh.com MAC algorithms in the affected configuration, and use unaffected algorithms like AES-GCM instead.

      Remediation

      -

      Upgrade Ubuntu:21.10 openldap to version 2.5.6+dfsg-1~exp1ubuntu1.1 or higher.

      +

      Upgrade golang.org/x/crypto/ssh to version 0.17.0 or higher.

      References


    -

    NULL Pointer Dereference

    +

    Information Exposure

    @@ -2466,17 +2299,20 @@

    NULL Pointer Dereference

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - krb5/libk5crypto3 + gnutls28/libgnutls30
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and krb5/libk5crypto3@1.18.3-6 + docker-image|quay.io/argoproj/argocd@v2.7.17 and gnutls28/libgnutls30@3.7.3-4ubuntu1.4
    @@ -2489,161 +2325,212 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - krb5/libk5crypto3@1.18.3-6 + gnutls28/libgnutls30@3.7.3-4ubuntu1.4
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - adduser@3.118ubuntu5 + docker-image|quay.io/argoproj/argocd@v2.7.17 - shadow/passwd@1:4.8.1-1ubuntu9 + apt@2.4.11 - pam/libpam-modules@1.3.1-5ubuntu11 - - libnsl/libnsl2@1.3.0-2build1 - - libtirpc/libtirpc3@1.3.2-2 - - krb5/libgssapi-krb5-2@1.18.3-6 - - krb5/libk5crypto3@1.18.3-6 + gnutls28/libgnutls30@3.7.3-4ubuntu1.4
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-1ubuntu9 - - pam/libpam-modules@1.3.1-5ubuntu11 + docker-image|quay.io/argoproj/argocd@v2.7.17 - libnsl/libnsl2@1.3.0-2build1 + gnupg2/dirmngr@2.2.27-3ubuntu2.1 - libtirpc/libtirpc3@1.3.2-2 - - krb5/libgssapi-krb5-2@1.18.3-6 - - krb5/libkrb5-3@1.18.3-6 - - krb5/libk5crypto3@1.18.3-6 + gnutls28/libgnutls30@3.7.3-4ubuntu1.4
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + git@1:2.34.1-1ubuntu1.10 - krb5/libkrb5-3@1.18.3-6 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - adduser@3.118ubuntu5 + git@1:2.34.1-1ubuntu1.10 - shadow/passwd@1:4.8.1-1ubuntu9 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - pam/libpam-modules@1.3.1-5ubuntu11 + openldap/libldap-2.5-0@2.5.16+dfsg-0ubuntu0.22.04.2 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 - libnsl/libnsl2@1.3.0-2build1 + git@1:2.34.1-1ubuntu1.10 - libtirpc/libtirpc3@1.3.2-2 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - krb5/libgssapi-krb5-2@1.18.3-6 + rtmpdump/librtmp1@2.4+20151223.gitfa8646d.1-2build4 - krb5/libkrb5-3@1.18.3-6 + gnutls28/libgnutls30@3.7.3-4ubuntu1.4
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    A flaw was found in GnuTLS. The Minerva attack is a cryptographic vulnerability that exploits deterministic behavior in systems like GnuTLS, leading to side-channel leaks. In specific scenarios, such as when using the GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE flag, it can result in a noticeable step in nonce size from 513 to 512 bits, exposing a potential timing side-channel.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 gnutls28.

    +

    References

    + + +
    + + + +
    +
    +

    Uncaught Exception

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gnutls28/libgnutls30 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.7.17 and gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - krb5/libgssapi-krb5-2@1.18.3-6 + gnutls28/libgnutls30@3.7.3-4ubuntu1.4
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - openssh/openssh-client@1:8.4p1-6ubuntu2.1 + apt@2.4.11 - krb5/libgssapi-krb5-2@1.18.3-6 + gnutls28/libgnutls30@3.7.3-4ubuntu1.4
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git@1:2.32.0-1ubuntu1 + gnupg2/dirmngr@2.2.27-3ubuntu2.1 - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 - - krb5/libgssapi-krb5-2@1.18.3-6 + gnutls28/libgnutls30@3.7.3-4ubuntu1.4
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + git@1:2.34.1-1ubuntu1.10 - libssh/libssh-4@0.9.6-1 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - krb5/libgssapi-krb5-2@1.18.3-6 + gnutls28/libgnutls30@3.7.3-4ubuntu1.4
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-1ubuntu9 + git@1:2.34.1-1ubuntu1.10 - pam/libpam-modules@1.3.1-5ubuntu11 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - libnsl/libnsl2@1.3.0-2build1 + openldap/libldap-2.5-0@2.5.16+dfsg-0ubuntu0.22.04.2 - libtirpc/libtirpc3@1.3.2-2 - - krb5/libgssapi-krb5-2@1.18.3-6 + gnutls28/libgnutls30@3.7.3-4ubuntu1.4
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + git@1:2.34.1-1ubuntu1.10 - meta-common-packages@meta + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - krb5/libkrb5support0@1.18.3-6 + rtmpdump/librtmp1@2.4+20151223.gitfa8646d.1-2build4 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 @@ -2655,32 +2542,28 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream krb5 package.

      -

      The Key Distribution Center (KDC) in MIT Kerberos 5 (aka krb5) before 1.18.5 and 1.19.x before 1.19.3 has a NULL pointer dereference in kdc/do_tgs_req.c via a FAST inner body that lacks a server field.

      +

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

      +

      A flaw has been discovered in GnuTLS where an application crash can be induced when attempting to verify a specially crafted .pem bundle using the "certtool --verify-chain" command.

      Remediation

      -

      There is no fixed version for Ubuntu:21.10 krb5.

      +

      There is no fixed version for Ubuntu:22.04 gnutls28.

      References


    -

    Improper Input Validation

    +

    MPL-2.0 license

    @@ -2691,17 +2574,20 @@

    Improper Input Validation

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argo-cd/v2 /usr/local/bin/argocd
    • - Vulnerable module: + Package Manager: golang +
    • +
    • + Module: - gzip + github.com/r3labs/diff
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and gzip@1.10-4ubuntu1 + github.com/argoproj/argo-cd/v2@* and github.com/r3labs/diff@v1.1.0
    @@ -2714,9 +2600,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + github.com/argoproj/argo-cd/v2@* - gzip@1.10-4ubuntu1 + github.com/r3labs/diff@v1.1.0 @@ -2727,35 +2613,17 @@

      Detailed paths


      -

      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream gzip package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      An arbitrary file write vulnerability was found in GNU gzip's zgrep utility. When zgrep is applied on the attacker's chosen file name (for example, a crafted file name), this can overwrite an attacker's content to an arbitrary attacker-selected file. This flaw occurs due to insufficient validation when processing filenames with two or more newlines where selected content and the target file names are embedded in crafted multi-line file names. This flaw allows a remote, low privileged attacker to force zgrep to write arbitrary files on the system.

      -

      Remediation

      -

      Upgrade Ubuntu:21.10 gzip to version 1.10-4ubuntu1.1 or higher.

      -

      References

      - +

      MPL-2.0 license


    -

    Arbitrary Code Injection

    +

    MPL-2.0 license

    @@ -2766,17 +2634,20 @@

    Arbitrary Code Injection

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argo-cd/v2 /usr/local/bin/argocd
    • - Vulnerable module: + Package Manager: golang +
    • +
    • + Module: - gnupg2/gpgv + github.com/hashicorp/go-version
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and gnupg2/gpgv@2.2.20-1ubuntu4 + github.com/argoproj/argo-cd/v2@* and github.com/hashicorp/go-version@v1.2.1
    @@ -2789,1829 +2660,30 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + github.com/argoproj/argo-cd/v2@* - gnupg2/gpgv@2.2.20-1ubuntu4 + github.com/hashicorp/go-version@v1.2.1
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - apt@2.3.9 - - gnupg2/gpgv@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpgv@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/dirmngr@2.2.20-1ubuntu4 - - gnupg2/gpgconf@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gpg@2.2.20-1ubuntu4 - - gnupg2/gpgconf@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpg-agent@2.2.20-1ubuntu4 - - gnupg2/gpgconf@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpgsm@2.2.20-1ubuntu4 - - gnupg2/gpgconf@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/dirmngr@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/dirmngr@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpg-wks-client@2.2.20-1ubuntu4 - - gnupg2/dirmngr@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg-l10n@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gnupg-l10n@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg-utils@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gnupg-utils@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gpg@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpg@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpg-wks-client@2.2.20-1ubuntu4 - - gnupg2/gpg@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpg-wks-server@2.2.20-1ubuntu4 - - gnupg2/gpg@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gpg-agent@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpg-agent@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpg-wks-client@2.2.20-1ubuntu4 - - gnupg2/gpg-agent@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpg-wks-server@2.2.20-1ubuntu4 - - gnupg2/gpg-agent@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gpg-wks-client@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpg-wks-client@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gpg-wks-server@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpg-wks-server@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gpgsm@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - gnupg2/gpgsm@2.2.20-1ubuntu4 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - gnupg2/gnupg@2.2.20-1ubuntu4 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream gnupg2 package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    GnuPG through 2.3.6, in unusual situations where an attacker possesses any secret-key information from a victim's keyring and other constraints (e.g., use of GPGME) are met, allows signature forgery via injection into the status line.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 gnupg2 to version 2.2.20-1ubuntu4.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Off-by-one Error

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - glibc/libc-bin -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and glibc/libc-bin@2.34-0ubuntu3 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - glibc/libc-bin@2.34-0ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - meta-common-packages@meta - - glibc/libc6@2.34-0ubuntu3 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream glibc package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    A flaw was found in glibc. An off-by-one buffer overflow and underflow in getcwd() may lead to memory corruption when the size of the buffer is exactly 1. A local attacker who can control the input buffer and size passed to getcwd() in a setuid program could use this flaw to potentially execute arbitrary code and escalate their privileges on the system.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 glibc to version 2.34-0ubuntu3.2 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Out-of-bounds Read

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - glibc/libc-bin -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and glibc/libc-bin@2.34-0ubuntu3 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - glibc/libc-bin@2.34-0ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - meta-common-packages@meta - - glibc/libc6@2.34-0ubuntu3 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream glibc package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    A flaw was found in glibc. The realpath() function can mistakenly return an unexpected value, potentially leading to information leakage and disclosure of sensitive data.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 glibc to version 2.34-0ubuntu3.2 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Uncontrolled Search Path Element

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - git/git-man -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - git/git-man@1:2.32.0-1ubuntu1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git-lfs@2.13.2-1 - - git@1:2.32.0-1ubuntu1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream git package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    Git for Windows is a fork of Git containing Windows-specific patches. This vulnerability affects users working on multi-user machines, where untrusted parties have write access to the same hard disk. Those untrusted parties could create the folder C:\.git, which would be picked up by Git operations run supposedly outside a repository while searching for a Git directory. Git would then respect any config in said Git directory. Git Bash users who set GIT_PS1_SHOWDIRTYSTATE are vulnerable as well. Users who installed posh-gitare vulnerable simply by starting a PowerShell. Users of IDEs such as Visual Studio are vulnerable: simply creating a new project would already read and respect the config specified in C:\.git\config. Users of the Microsoft fork of Git are vulnerable simply by starting a Git Bash. The problem has been patched in Git for Windows v2.35.2. Users unable to upgrade may create the folder .git on all drives where Git commands are run, and remove read/write access from those folders as a workaround. Alternatively, define or extend GIT_CEILING_DIRECTORIES to cover the parent directory of the user profile, e.g. C:\Users if the user profile is located in C:\Users\my-user-name.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 git to version 1:2.32.0-1ubuntu1.2 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Uncontrolled Search Path Element

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - git/git-man -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - git/git-man@1:2.32.0-1ubuntu1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git-lfs@2.13.2-1 - - git@1:2.32.0-1ubuntu1 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream git package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    Git is a distributed revision control system. Git prior to versions 2.37.1, 2.36.2, 2.35.4, 2.34.4, 2.33.4, 2.32.3, 2.31.4, and 2.30.5, is vulnerable to privilege escalation in all platforms. An unsuspecting user could still be affected by the issue reported in CVE-2022-24765, for example when navigating as root into a shared tmp directory that is owned by them, but where an attacker could create a git repository. Versions 2.37.1, 2.36.2, 2.35.4, 2.34.4, 2.33.4, 2.32.3, 2.31.4, and 2.30.5 contain a patch for this issue. The simplest way to avoid being affected by the exploit described in the example is to avoid running git as root (or an Administrator in Windows), and if needed to reduce its use to a minimum. While a generic workaround is not possible, a system could be hardened from the exploit described in the example by removing any such repository if it exists already and creating one as root to block any future attacks.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 git to version 1:2.32.0-1ubuntu1.3 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - expat/libexpat1 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    In doProlog in xmlparse.c in Expat (aka libexpat) before 2.4.3, an integer overflow exists for m_groupSize.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - expat/libexpat1 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    storeAtts in xmlparse.c in Expat (aka libexpat) before 2.4.3 has an integer overflow.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - expat/libexpat1 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    nextScaffoldPart in xmlparse.c in Expat (aka libexpat) before 2.4.3 has an integer overflow.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - expat/libexpat1 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    lookup in xmlparse.c in Expat (aka libexpat) before 2.4.3 has an integer overflow.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - expat/libexpat1 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    defineAttribute in xmlparse.c in Expat (aka libexpat) before 2.4.3 has an integer overflow.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - expat/libexpat1 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    build_model in xmlparse.c in Expat (aka libexpat) before 2.4.3 has an integer overflow.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - expat/libexpat1 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    addBinding in xmlparse.c in Expat (aka libexpat) before 2.4.3 has an integer overflow.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - expat/libexpat1 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    Expat (aka libexpat) before 2.4.4 has a signed integer overflow in XML_GetBuffer, for configurations with a nonzero XML_CONTEXT_BYTES.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - expat/libexpat1 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    Expat (aka libexpat) before 2.4.4 has an integer overflow in the doProlog function.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - expat/libexpat1 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    In Expat (aka libexpat) before 2.4.5, there is an integer overflow in storeRawNames.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.3 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Integer Overflow or Wraparound

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - expat/libexpat1 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    In Expat (aka libexpat) before 2.4.5, there is an integer overflow in copyString.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.3 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Resource Exhaustion

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - expat/libexpat1 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 - - expat/libexpat1@2.4.1-2 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    In Expat (aka libexpat) before 2.4.5, an attacker can trigger stack exhaustion in build_model via a large nesting depth in the DTD element.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.3 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Out-of-bounds Read

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - e2fsprogs/libcom-err2 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and e2fsprogs/libcom-err2@1.46.3-1ubuntu3 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - e2fsprogs/libcom-err2@1.46.3-1ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - e2fsprogs@1.46.3-1ubuntu3 - - e2fsprogs/libcom-err2@1.46.3-1ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - e2fsprogs@1.46.3-1ubuntu3 - - e2fsprogs/libss2@1.46.3-1ubuntu3 - - e2fsprogs/libcom-err2@1.46.3-1ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-1ubuntu9 - - pam/libpam-modules@1.3.1-5ubuntu11 - - libnsl/libnsl2@1.3.0-2build1 - - libtirpc/libtirpc3@1.3.2-2 - - krb5/libgssapi-krb5-2@1.18.3-6 - - e2fsprogs/libcom-err2@1.46.3-1ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-1ubuntu9 - - pam/libpam-modules@1.3.1-5ubuntu11 - - libnsl/libnsl2@1.3.0-2build1 - - libtirpc/libtirpc3@1.3.2-2 - - krb5/libgssapi-krb5-2@1.18.3-6 - - krb5/libkrb5-3@1.18.3-6 - - e2fsprogs/libcom-err2@1.46.3-1ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - e2fsprogs/libext2fs2@1.46.3-1ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - e2fsprogs@1.46.3-1ubuntu3 - - e2fsprogs/libext2fs2@1.46.3-1ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - e2fsprogs/libss2@1.46.3-1ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - e2fsprogs@1.46.3-1ubuntu3 - - e2fsprogs/libss2@1.46.3-1ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - e2fsprogs/logsave@1.46.3-1ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - e2fsprogs@1.46.3-1ubuntu3 - - e2fsprogs/logsave@1.46.3-1ubuntu3 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - e2fsprogs@1.46.3-1ubuntu3 - - - -
    • -
    +

    -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream e2fsprogs package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    An out-of-bounds read/write vulnerability was found in e2fsprogs 1.46.5. This issue leads to a segmentation fault and possibly arbitrary code execution via a specially crafted filesystem.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 e2fsprogs to version 1.46.3-1ubuntu3.1 or higher.

    -

    References

    - +

    MPL-2.0 license


    -

    Directory Traversal

    +

    MPL-2.0 license

    @@ -4622,18 +2694,21 @@

    Directory Traversal

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argo-cd/v2 /usr/local/bin/argocd
    • - Vulnerable module: + Package Manager: golang +
    • +
    • + Module: - dpkg + github.com/hashicorp/go-retryablehttp
    • Introduced through: + github.com/argoproj/argo-cd/v2@* and github.com/hashicorp/go-retryablehttp@v0.7.0 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, meta-common-packages@meta and others
    @@ -4645,11 +2720,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + github.com/argoproj/argo-cd/v2@* - meta-common-packages@meta - - dpkg@1.20.9ubuntu2 + github.com/hashicorp/go-retryablehttp@v0.7.0 @@ -4660,33 +2733,17 @@

      Detailed paths


      -

      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream dpkg package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      Dpkg::Source::Archive in dpkg, the Debian package management system, before version 1.21.8, 1.20.10, 1.19.8, 1.18.26 is prone to a directory traversal vulnerability. When extracting untrusted source packages in v2 and v3 source package formats that include a debian.tar, the in-place extraction can lead to directory traversal situations on specially crafted orig.tar and debian.tar tarballs.

      -

      Remediation

      -

      Upgrade Ubuntu:21.10 dpkg to version 1.20.9ubuntu2.2 or higher.

      -

      References

      - +

      MPL-2.0 license


    -

    Improper Authentication

    +

    MPL-2.0 license

    @@ -4697,18 +2754,21 @@

    Improper Authentication

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argo-cd/v2 /usr/local/bin/argocd
    • - Vulnerable module: + Package Manager: golang +
    • +
    • + Module: - curl/libcurl3-gnutls + github.com/hashicorp/go-cleanhttp
    • Introduced through: + github.com/argoproj/argo-cd/v2@* and github.com/hashicorp/go-cleanhttp@v0.5.2 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others
    @@ -4720,11 +2780,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + github.com/argoproj/argo-cd/v2@* - git@1:2.32.0-1ubuntu1 - - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + github.com/hashicorp/go-cleanhttp@v0.5.2 @@ -4735,31 +2793,17 @@

      Detailed paths


      -

      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream curl package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      An improper authentication vulnerability exists in curl 7.33.0 to and including 7.82.0 which might allow reuse OAUTH2-authenticated connections without properly making sure that the connection was authenticated with the same credentials as set for this transfer. This affects SASL-enabled protocols: SMPTP(S), IMAP(S), POP3(S) and LDAP(S) (openldap only).

      -

      Remediation

      -

      Upgrade Ubuntu:21.10 curl to version 7.74.0-1.3ubuntu2.1 or higher.

      -

      References

      - +

      MPL-2.0 license


    -

    Insufficiently Protected Credentials

    +

    MPL-2.0 license

    @@ -4770,18 +2814,21 @@

    Insufficiently Protected Credentials

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argo-cd/v2 /usr/local/bin/argocd
    • - Vulnerable module: + Package Manager: golang +
    • +
    • + Module: - curl/libcurl3-gnutls + github.com/gosimple/slug
    • Introduced through: + github.com/argoproj/argo-cd/v2@* and github.com/gosimple/slug@v1.13.1 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others
    @@ -4793,11 +2840,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 + github.com/argoproj/argo-cd/v2@* - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + github.com/gosimple/slug@v1.13.1 @@ -4808,30 +2853,17 @@

      Detailed paths


      -

      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream curl package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      An insufficiently protected credentials vulnerability exists in curl 4.9 to and include curl 7.82.0 are affected that could allow an attacker to extract credentials when follows HTTP(S) redirects is used with authentication could leak credentials to other services that exist on different protocols or port numbers.

      -

      Remediation

      -

      Upgrade Ubuntu:21.10 curl to version 7.74.0-1.3ubuntu2.1 or higher.

      -

      References

      - +

      MPL-2.0 license


    -

    Improper Certificate Validation

    +

    Denial of Service (DoS)

    @@ -4842,18 +2874,21 @@

    Improper Certificate Validation

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/helm/v3 /usr/local/bin/helm +
    • +
    • + Package Manager: golang
    • Vulnerable module: - curl/libcurl3-gnutls + github.com/docker/distribution/registry/api/v2
    • Introduced through: + helm.sh/helm/v3@* and github.com/docker/distribution/registry/api/v2@v2.8.1+incompatible - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others
    @@ -4865,11 +2900,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 + helm.sh/helm/v3@* - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + github.com/docker/distribution/registry/api/v2@v2.8.1+incompatible @@ -4880,31 +2913,26 @@

      Detailed paths


      -

      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream curl package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      libcurl would reuse a previously created connection even when a TLS or SSHrelated option had been changed that should have prohibited reuse.libcurl keeps previously used connections in a connection pool for subsequenttransfers to reuse if one of them matches the setup. However, several TLS andSSH settings were left out from the configuration match checks, making themmatch too easily.

      +

      Overview

      +

      Affected versions of this package are vulnerable to Denial of Service (DoS) due to improper validation of the value passed to the n parameter in the /v2/_catalog endpoint. + Exploiting this vulnerability is possible by sending a crafted malicious request to the /v2/_catalog API endpoint, which results in an allocation of a massive string array and excessive use of memory.

      Remediation

      -

      Upgrade Ubuntu:21.10 curl to version 7.74.0-1.3ubuntu2.2 or higher.

      +

      Upgrade github.com/docker/distribution/registry/api/v2 to version 2.8.2-beta.1 or higher.

      References


    -

    Out-of-bounds Write

    +

    Resource Exhaustion

    @@ -4915,18 +2943,21 @@

    Out-of-bounds Write

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - curl/libcurl3-gnutls + expat/libexpat1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others + docker-image|quay.io/argoproj/argocd@v2.7.17, git@1:2.34.1-1ubuntu1.10 and others
    @@ -4938,11 +2969,11 @@

    Detailed paths

    -

    Incorrect Default Permissions

    +

    CVE-2024-28757

    @@ -4992,18 +3017,21 @@

    Incorrect Default Permissions

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - curl/libcurl3-gnutls + expat/libexpat1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others + docker-image|quay.io/argoproj/argocd@v2.7.17, git@1:2.34.1-1ubuntu1.10 and others
    @@ -5015,11 +3043,11 @@

    Detailed paths

    -

    Allocation of Resources Without Limits or Throttling

    +

    Out-of-bounds Write

    @@ -5068,18 +3094,21 @@

    Allocation of Resources Without Limits or Throttling

  • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
  • +
  • + Package Manager: ubuntu:22.04
  • Vulnerable module: - curl/libcurl3-gnutls + bash
  • Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 and bash@5.1-6ubuntu1 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others
  • @@ -5091,11 +3120,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + bash@5.1-6ubuntu1 @@ -5107,57 +3134,51 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream curl package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      curl < 7.84.0 supports "chained" HTTP compression algorithms, meaning that a serverresponse can be compressed multiple times and potentially with different algorithms. The number of acceptable "links" in this "decompression chain" was unbounded, allowing a malicious server to insert a virtually unlimited number of compression steps.The use of such a decompression chain could result in a "malloc bomb", makingcurl end up spending enormous amounts of allocated heap memory, or trying toand returning out of memory errors.

      +

      Note: Versions mentioned in the description apply only to the upstream bash package and not the bash package as distributed by Ubuntu. + 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

      -

      Upgrade Ubuntu:21.10 curl to version 7.74.0-1.3ubuntu2.3 or higher.

      +

      Upgrade Ubuntu:22.04 bash to version 5.1-6ubuntu1.1 or higher.

      References


    -
    -

    Allocation of Resources Without Limits or Throttling

    +
    +

    CVE-2023-7008

    -
    - medium severity +
    + low severity

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - curl/libcurl3-gnutls + systemd/libsystemd0
    • Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 and systemd/libsystemd0@249.11-0ubuntu3.12 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others
    @@ -5169,316 +3190,110 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + systemd/libsystemd0@249.11-0ubuntu3.12
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream curl package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    A malicious server can serve excessive amounts of Set-Cookie: headers in a HTTP response to curl and curl < 7.84.0 stores all of them. A sufficiently large amount of (big) cookies make subsequent HTTP requests to this, or other servers to which the cookies match, create requests that become larger than the threshold that curl uses internally to avoid sending crazy large requests (1048576 bytes) and instead returns an error.This denial state might remain for as long as the same cookies are kept, match and haven't expired. Due to cookie matching rules, a server on foo.example.com can set cookies that also would match for bar.example.com, making it it possible for a "sister server" to effectively cause a denial of service for a sibling site on the same second level domain using this method.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 curl to version 7.74.0-1.3ubuntu2.3 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    NULL Pointer Dereference

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - tar -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, meta-common-packages@meta and others -
    • -
    - -
    - - -

    Detailed paths

    - -
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - meta-common-packages@meta + apt@2.4.11 - tar@1.34+dfsg-1build1 + systemd/libsystemd0@249.11-0ubuntu3.12
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream tar package.

    -

    pax_decode_header in sparse.c in GNU Tar before 1.32 had a NULL pointer dereference when parsing certain archives that have malformed extended headers.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:21.10 tar.

    -

    References

    - - -
    - - - -
    -
    -

    CVE-2021-36690

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - sqlite3/libsqlite3-0 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, gnupg2/gpg@2.2.20-1ubuntu4 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - gnupg2/gpg@2.2.20-1ubuntu4 + procps/libprocps8@2:3.3.17-6ubuntu2.1 - sqlite3/libsqlite3-0@3.35.5-1 + systemd/libsystemd0@249.11-0ubuntu3.12
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream sqlite3 package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    ** DISPUTED ** A segmentation fault can occur in the sqlite3.exe command-line component of SQLite 3.36.0 via the idxGetTableInfo function when there is a crafted SQL query. NOTE: the vendor disputes the relevance of this report because a sqlite3.exe user already has full privileges (e.g., is intentionally allowed to execute commands). This report does NOT imply any problem in the SQLite library.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 sqlite3 to version 3.35.5-1ubuntu0.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    CVE-2020-9991

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - sqlite3/libsqlite3-0 -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, gnupg2/gpg@2.2.20-1ubuntu4 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - gnupg2/gpg@2.2.20-1ubuntu4 + util-linux@2.37.2-4ubuntu3 - sqlite3/libsqlite3-0@3.35.5-1 + systemd/libsystemd0@249.11-0ubuntu3.12
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream sqlite3 package.

    -

    This issue was addressed with improved checks. This issue is fixed in macOS Big Sur 11.0.1, watchOS 7.0, iOS 14.0 and iPadOS 14.0, iCloud for Windows 7.21, tvOS 14.0. A remote attacker may be able to cause a denial of service.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:21.10 sqlite3.

    -

    References

    - - -
    - - - -
    -
    -

    Information Exposure

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - sqlite3/libsqlite3-0 -
    • - -
    • Introduced through: - +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + util-linux/bsdutils@1:2.37.2-4ubuntu3 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, gnupg2/gpg@2.2.20-1ubuntu4 and others -
    • -
    + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + -
    +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + systemd/libudev1@249.11-0ubuntu3.12 + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + libfido2/libfido2-1@1.10.0-1 + + systemd/libudev1@249.11-0ubuntu3.12 + + -

    Detailed paths

    +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + util-linux@2.37.2-4ubuntu3 + + systemd/libudev1@249.11-0ubuntu3.12 + + -
  • -

    Time-of-check Time-of-use (TOCTOU)

    +

    Arbitrary Code Injection

    @@ -5526,7 +3340,10 @@

    Time-of-check Time-of-use (TOCTOU)

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: @@ -5536,7 +3353,7 @@

      Time-of-check Time-of-use (TOCTOU)

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and shadow/passwd@1:4.8.1-1ubuntu9 + docker-image|quay.io/argoproj/argocd@v2.7.17 and shadow/passwd@1:4.8.1-2ubuntu2.1
    @@ -5549,53 +3366,40 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - shadow/passwd@1:4.8.1-1ubuntu9 + shadow/passwd@1:4.8.1-2ubuntu2.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 adduser@3.118ubuntu5 - shadow/passwd@1:4.8.1-1ubuntu9 + shadow/passwd@1:4.8.1-2ubuntu2.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - openssh/openssh-client@1:8.4p1-6ubuntu2.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - shadow/passwd@1:4.8.1-1ubuntu9 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + openssh/openssh-client@1:8.9p1-3ubuntu0.6 - shadow/login@1:4.8.1-1ubuntu9 + shadow/passwd@1:4.8.1-2ubuntu2.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux/mount@2.36.1-8ubuntu2 - - util-linux@2.36.1-8ubuntu2 - - shadow/login@1:4.8.1-1ubuntu9 + shadow/login@1:4.8.1-2ubuntu2.1 @@ -5607,29 +3411,29 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream shadow package.

      -

      shadow: TOCTOU (time-of-check time-of-use) race condition when copying and removing directory trees

      +

      Note: Versions mentioned in the description apply only to the upstream shadow package and not the shadow package as distributed by Ubuntu. + 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:21.10 shadow.

      +

      There is no fixed version for Ubuntu:22.04 shadow.

      References


    -

    Out-of-bounds Read

    +

    Improper Authentication

    @@ -5640,17 +3444,20 @@

    Out-of-bounds Read

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - pcre3/libpcre3 + shadow/passwd
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and pcre3/libpcre3@2:8.39-13build3 + docker-image|quay.io/argoproj/argocd@v2.7.17 and shadow/passwd@1:4.8.1-2ubuntu2.1
    @@ -5663,20 +3470,40 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + adduser@3.118ubuntu5 - pcre3/libpcre3@2:8.39-13build3 + shadow/passwd@1:4.8.1-2ubuntu2.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 - grep@3.7-0ubuntu1 + shadow/passwd@1:4.8.1-2ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 - pcre3/libpcre3@2:8.39-13build3 + shadow/login@1:4.8.1-2ubuntu2.1 @@ -5688,28 +3515,24 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream pcre3 package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      libpcre in PCRE before 8.43 allows a subject buffer over-read in JIT when UTF is disabled, and \X or \R has more than one fixed quantifier, a related issue to CVE-2019-20454.

      +

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

      +

      A flaw was found in shadow-utils. When asking for a new password, shadow-utils asks the password twice. If the password fails on the second attempt, shadow-utils fails in cleaning the buffer used to store the first entry. This may allow an attacker with enough access to retrieve the password from the memory.

      Remediation

      -

      Upgrade Ubuntu:21.10 pcre3 to version 2:8.39-13ubuntu0.21.10.1 or higher.

      +

      Upgrade Ubuntu:22.04 shadow to version 1:4.8.1-2ubuntu2.2 or higher.

      References


    @@ -5725,7 +3548,10 @@

    Uncontrolled Recursion

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: @@ -5735,7 +3561,7 @@

      Uncontrolled Recursion

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and pcre3/libpcre3@2:8.39-13build3 + docker-image|quay.io/argoproj/argocd@v2.7.17 and pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1
    @@ -5748,20 +3574,20 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - pcre3/libpcre3@2:8.39-13build3 + pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - grep@3.7-0ubuntu1 + grep@3.7-1build1 - pcre3/libpcre3@2:8.39-13build3 + pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 @@ -5773,10 +3599,11 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream pcre3 package.

      +

      Note: Versions mentioned in the description apply only to the upstream pcre3 package and not the pcre3 package as distributed by Ubuntu. + 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:21.10 pcre3.

      +

      There is no fixed version for Ubuntu:22.04 pcre3.

      References


    -

    Out-of-bounds Read

    +

    Release of Invalid Pointer or Reference

    @@ -5806,18 +3636,21 @@

    Out-of-bounds Read

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - pcre2/libpcre2-8-0 + patch
    • Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 and patch@2.7.6-7build2 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, meta-common-packages@meta and others
    @@ -5829,11 +3662,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - meta-common-packages@meta + docker-image|quay.io/argoproj/argocd@v2.7.17 - pcre2/libpcre2-8-0@10.37-0ubuntu2 + patch@2.7.6-7build2 @@ -5845,31 +3676,26 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream pcre2 package.

      -

      An out-of-bounds read vulnerability was discovered in the PCRE2 library in the get_recurse_data_length() function of the pcre2_jit_compile.c file. This issue affects recursions in JIT-compiled regular expressions caused by duplicate data transfers.

      +

      Note: Versions mentioned in the description apply only to the upstream patch package and not the patch 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.

      Remediation

      -

      There is no fixed version for Ubuntu:21.10 pcre2.

      +

      There is no fixed version for Ubuntu:22.04 patch.

      References


    -

    Out-of-bounds Read

    +

    Double Free

    @@ -5880,18 +3706,21 @@

    Out-of-bounds Read

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - pcre2/libpcre2-8-0 + patch
    • Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 and patch@2.7.6-7build2 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, meta-common-packages@meta and others
    @@ -5903,11 +3732,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - meta-common-packages@meta + docker-image|quay.io/argoproj/argocd@v2.7.17 - pcre2/libpcre2-8-0@10.37-0ubuntu2 + patch@2.7.6-7build2 @@ -5919,32 +3746,31 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream pcre2 package.

      -

      An out-of-bounds read vulnerability was discovered in the PCRE2 library in the compile_xclass_matchingpath() function of the pcre2_jit_compile.c file. This involves a unicode property matching issue in JIT-compiled regular expressions. The issue occurs because the character was not fully read in case-less matching within JIT.

      +

      Note: Versions mentioned in the description apply only to the upstream patch package and not the patch 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.

      Remediation

      -

      There is no fixed version for Ubuntu:21.10 pcre2.

      +

      There is no fixed version for Ubuntu:22.04 patch.

      References


    -

    Double Free

    +

    Improper Check for Unusual or Exceptional Conditions

    @@ -5955,17 +3781,20 @@

    Double Free

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - patch + openssl/libssl3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and patch@2.7.6-7 + docker-image|quay.io/argoproj/argocd@v2.7.17 and openssl/libssl3@3.0.2-0ubuntu1.13
    @@ -5978,9 +3807,113 @@

    Detailed paths

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

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream patch package.

      -

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

      +

      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: Generating excessively long X9.42 DH keys or checking + excessively long X9.42 DH keys or parameters may be very slow.

      +

      Impact summary: Applications that use the functions DH_generate_key() to + generate an X9.42 DH key may experience long delays. Likewise, applications + that use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check() + to check an X9.42 DH key or X9.42 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.

      +

      While DH_check() performs all the necessary checks (as of CVE-2023-3817), + DH_check_pub_key() doesn't make any of these checks, and is therefore + vulnerable for excessively large P and Q parameters.

      +

      Likewise, while DH_generate_key() performs a check for an excessively large + P, it doesn't check for an excessively large Q.

      +

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

      +

      DH_generate_key() and DH_check_pub_key() are also 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_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().

      +

      Also vulnerable are the OpenSSL pkey command line application when using the + "-pubcheck" option, as well as the OpenSSL genpkey command line application.

      +

      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:21.10 patch.

      +

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

      References


    -

    Release of Invalid Pointer or Reference

    +

    Out-of-bounds Write

    @@ -6026,17 +3984,20 @@

    Release of Invalid Pointer or Reference

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - patch + openssl/libssl3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and patch@2.7.6-7 + docker-image|quay.io/argoproj/argocd@v2.7.17 and openssl/libssl3@3.0.2-0ubuntu1.13
    @@ -6046,12 +4007,116 @@

    Release of Invalid Pointer or Reference

    Detailed paths

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

        Detailed paths


        NVD Description

        -

        Note: Versions mentioned in the description apply to the upstream patch package.

        -

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

        +

        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 POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

        +

        Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

        +

        The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

        +

        The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

        +

        The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

        Remediation

        -

        There is no fixed version for Ubuntu:21.10 patch.

        +

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

        References


    -

    CVE-2021-41617

    +

    CVE-2023-6237

    @@ -6092,17 +4189,20 @@

    CVE-2021-41617

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - openssh/openssh-client + openssl/libssl3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and openssh/openssh-client@1:8.4p1-6ubuntu2.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 and openssl/libssl3@3.0.2-0ubuntu1.13
    @@ -6115,9 +4215,113 @@

    Detailed paths

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

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream openssh package.

      -

      sshd in OpenSSH 6.2 through 8.x before 8.8, when certain non-default configurations are used, allows privilege escalation because supplemental groups are not initialized as expected. Helper programs for AuthorizedKeysCommand and AuthorizedPrincipalsCommand may run with privileges associated with group memberships of the sshd process, if the configuration specifies running the command as a different user.

      +

      This vulnerability has not been analyzed by NVD yet.

      Remediation

      -

      There is no fixed version for Ubuntu:21.10 openssh.

      +

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

      References


    -

    Information Exposure

    +

    CVE-2024-0727

    @@ -6168,17 +4360,20 @@

    Information Exposure

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - openssh/openssh-client + openssl/libssl3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and openssh/openssh-client@1:8.4p1-6ubuntu2.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 and openssl/libssl3@3.0.2-0ubuntu1.13
    @@ -6191,9 +4386,113 @@

    Detailed paths

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

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream openssh package.

      -

      The client side in OpenSSH 5.7 through 8.4 has an Observable Discrepancy leading to an information leak in the algorithm negotiation. This allows man-in-the-middle attackers to target initial connection attempts (where no host key for the server has been cached by the client). NOTE: some reports state that 8.5 and 8.6 are also affected.

      +

      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: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

      +

      Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

      +

      A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

      +

      OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

      +

      We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

      +

      The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

      Remediation

      -

      There is no fixed version for Ubuntu:21.10 openssh.

      +

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

      References


    -

    Out-of-bounds Read

    +

    CVE-2023-50495

    @@ -6241,7 +4555,10 @@

    Out-of-bounds Read

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: @@ -6251,7 +4568,7 @@

      Out-of-bounds Read

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and ncurses/libtinfo6@6.2+20201114-2build1 + docker-image|quay.io/argoproj/argocd@v2.7.17 and ncurses/libtinfo6@6.3-2ubuntu0.1
    @@ -6264,202 +4581,200 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - ncurses/libtinfo6@6.2+20201114-2build1 + ncurses/libtinfo6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - bash@5.1-3ubuntu2 + bash@5.1-6ubuntu1 - ncurses/libtinfo6@6.2+20201114-2build1 + ncurses/libtinfo6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - ncurses/libncursesw6@6.2+20201114-2build1 + ncurses/libncursesw6@6.3-2ubuntu0.1 - ncurses/libtinfo6@6.2+20201114-2build1 + ncurses/libtinfo6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - less@551-2 + less@590-1ubuntu0.22.04.1 - ncurses/libtinfo6@6.2+20201114-2build1 + ncurses/libtinfo6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - libedit/libedit2@3.1-20191231-2build1 + libedit/libedit2@3.1-20210910-1build1 - ncurses/libtinfo6@6.2+20201114-2build1 + ncurses/libtinfo6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - ncurses/libncurses6@6.2+20201114-2build1 + ncurses/libncurses6@6.3-2ubuntu0.1 - ncurses/libtinfo6@6.2+20201114-2build1 + ncurses/libtinfo6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - ncurses/ncurses-bin@6.2+20201114-2build1 + ncurses/ncurses-bin@6.3-2ubuntu0.1 - ncurses/libtinfo6@6.2+20201114-2build1 + ncurses/libtinfo6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - procps@2:3.3.17-5ubuntu3 + procps@2:3.3.17-6ubuntu2.1 - ncurses/libtinfo6@6.2+20201114-2build1 + ncurses/libtinfo6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - util-linux/mount@2.36.1-8ubuntu2 + docker-image|quay.io/argoproj/argocd@v2.7.17 - util-linux@2.36.1-8ubuntu2 + util-linux@2.37.2-4ubuntu3 - ncurses/libtinfo6@6.2+20201114-2build1 + ncurses/libtinfo6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - gnupg2/gpg@2.2.20-1ubuntu4 + gnupg2/gpg@2.2.27-3ubuntu2.1 - gnupg2/gpgconf@2.2.20-1ubuntu4 + gnupg2/gpgconf@2.2.27-3ubuntu2.1 - readline/libreadline8@8.1-2 + readline/libreadline8@8.1.2-1 - ncurses/libtinfo6@6.2+20201114-2build1 + ncurses/libtinfo6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - gnupg2/gnupg@2.2.20-1ubuntu4 + gnupg2/gnupg@2.2.27-3ubuntu2.1 - gnupg2/gpg-agent@2.2.20-1ubuntu4 + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - pinentry/pinentry-curses@1.1.1-1 + pinentry/pinentry-curses@1.1.1-1build2 - ncurses/libtinfo6@6.2+20201114-2build1 + ncurses/libtinfo6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - ncurses/libncursesw6@6.2+20201114-2build1 + ncurses/libncursesw6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - procps@2:3.3.17-5ubuntu3 + procps@2:3.3.17-6ubuntu2.1 - ncurses/libncursesw6@6.2+20201114-2build1 + ncurses/libncursesw6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - gnupg2/gnupg@2.2.20-1ubuntu4 + gnupg2/gnupg@2.2.27-3ubuntu2.1 - gnupg2/gpg-agent@2.2.20-1ubuntu4 + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - pinentry/pinentry-curses@1.1.1-1 + pinentry/pinentry-curses@1.1.1-1build2 - ncurses/libncursesw6@6.2+20201114-2build1 + ncurses/libncursesw6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - ncurses/libncurses6@6.2+20201114-2build1 + ncurses/libncurses6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - procps@2:3.3.17-5ubuntu3 + procps@2:3.3.17-6ubuntu2.1 - ncurses/libncurses6@6.2+20201114-2build1 + ncurses/libncurses6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - ncurses/ncurses-base@6.2+20201114-2build1 + ncurses/ncurses-base@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - ncurses/ncurses-bin@6.2+20201114-2build1 + ncurses/ncurses-bin@6.3-2ubuntu0.1 @@ -6471,29 +4786,29 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream ncurses package.

      -

      ncurses 6.3 before patch 20220416 has an out-of-bounds read and segmentation violation in convert_strings in tinfo/read_entry.c in the terminfo library.

      +

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

      +

      NCurse v6.4-20230418 was discovered to contain a segmentation fault via the component _nc_wrap_entry().

      Remediation

      -

      There is no fixed version for Ubuntu:21.10 ncurses.

      +

      There is no fixed version for Ubuntu:22.04 ncurses.

      References


    -

    Out-of-bounds Read

    +

    CVE-2023-45918

    @@ -6504,17 +4819,20 @@

    Out-of-bounds Read

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - libsepol/libsepol1 + ncurses/libtinfo6
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and libsepol/libsepol1@3.1-1ubuntu2 + docker-image|quay.io/argoproj/argocd@v2.7.17 and ncurses/libtinfo6@6.3-2ubuntu0.1
    @@ -6524,199 +4842,203 @@

    Out-of-bounds Read

    Detailed paths

    -
      +
        +
      • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
      • +
      • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + bash@5.1-6ubuntu1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
      • +
      • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
      • +
      • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + less@590-1ubuntu0.22.04.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
      • +
      • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + libedit/libedit2@3.1-20210910-1build1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
      • +
      • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
      • +
      • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + ncurses/ncurses-bin@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
      • +
      • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
      • +
      • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + util-linux@2.37.2-4ubuntu3 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
      • +
      • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + readline/libreadline8@8.1.2-1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
      • +
      • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + pinentry/pinentry-curses@1.1.1-1build2 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
      • +
      • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
      • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + procps@2:3.3.17-6ubuntu2.1 - libsepol/libsepol1@3.1-1ubuntu2 + ncurses/libncursesw6@6.3-2ubuntu0.1
      • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - adduser@3.118ubuntu5 + gnupg2/gnupg@2.2.27-3ubuntu2.1 - shadow/passwd@1:4.8.1-1ubuntu9 + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - libsemanage/libsemanage1@3.1-1ubuntu2 + pinentry/pinentry-curses@1.1.1-1build2 - libsepol/libsepol1@3.1-1ubuntu2 + ncurses/libncursesw6@6.3-2ubuntu0.1
      • -
      - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream libsepol package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    The CIL compiler in SELinux 3.2 has a heap-based buffer over-read in ebitmap_match_any (called indirectly from cil_check_neverallow). This occurs because there is sometimes a lack of checks for invalid statements in an optional block.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 libsepol to version 3.1-1ubuntu2.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Use After Free

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - libsepol/libsepol1 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and libsepol/libsepol1@3.1-1ubuntu2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - libsepol/libsepol1@3.1-1ubuntu2 + ncurses/libncurses6@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-1ubuntu9 + procps@2:3.3.17-6ubuntu2.1 - libsemanage/libsemanage1@3.1-1ubuntu2 - - libsepol/libsepol1@3.1-1ubuntu2 + ncurses/libncurses6@6.3-2ubuntu0.1
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream libsepol package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    The CIL compiler in SELinux 3.2 has a use-after-free in __cil_verify_classperms (called from __verify_map_perm_classperms and hashtab_map).

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 libsepol to version 3.1-1ubuntu2.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Use After Free

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - libsepol/libsepol1 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and libsepol/libsepol1@3.1-1ubuntu2 - -
    • -
    - -
    - - -

    Detailed paths

    - -
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - libsepol/libsepol1@3.1-1ubuntu2 + ncurses/ncurses-base@6.3-2ubuntu0.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - adduser@3.118ubuntu5 + docker-image|quay.io/argoproj/argocd@v2.7.17 - shadow/passwd@1:4.8.1-1ubuntu9 - - libsemanage/libsemanage1@3.1-1ubuntu2 - - libsepol/libsepol1@3.1-1ubuntu2 + ncurses/ncurses-bin@6.3-2ubuntu0.1 @@ -6728,29 +5050,27 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream libsepol package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      The CIL compiler in SELinux 3.2 has a use-after-free in cil_reset_classpermission (called from cil_reset_classperms_set and cil_reset_classperms_list).

      +

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

      +

      ncurses 6.4-20230610 has a NULL pointer dereference in tgetstr in tinfo/lib_termcap.c.

      Remediation

      -

      Upgrade Ubuntu:21.10 libsepol to version 3.1-1ubuntu2.1 or higher.

      +

      There is no fixed version for Ubuntu:22.04 ncurses.

      References


    -

    Use After Free

    +

    Resource Exhaustion

    @@ -6761,17 +5081,20 @@

    Use After Free

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - libsepol/libsepol1 + libzstd/libzstd1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and libsepol/libsepol1@3.1-1ubuntu2 + docker-image|quay.io/argoproj/argocd@v2.7.17 and libzstd/libzstd1@1.4.8+dfsg-3build1
    @@ -6784,24 +5107,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - libsepol/libsepol1@3.1-1ubuntu2 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-1ubuntu9 - - libsemanage/libsemanage1@3.1-1ubuntu2 - - libsepol/libsepol1@3.1-1ubuntu2 + libzstd/libzstd1@1.4.8+dfsg-3build1 @@ -6813,24 +5121,28 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream libsepol package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      The CIL compiler in SELinux 3.2 has a use-after-free in __cil_verify_classperms (called from __cil_verify_classpermission and __cil_pre_verify_helper).

      +

      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

      -

      Upgrade Ubuntu:21.10 libsepol to version 3.1-1ubuntu2.1 or higher.

      +

      There is no fixed version for Ubuntu:22.04 libzstd.

      References


    @@ -6846,7 +5158,10 @@

    Integer Overflow or Wraparound

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: @@ -6856,7 +5171,7 @@

      Integer Overflow or Wraparound

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and krb5/libk5crypto3@1.18.3-6 + docker-image|quay.io/argoproj/argocd@v2.7.17 and krb5/libk5crypto3@1.19.2-2ubuntu0.3
    @@ -6869,161 +5184,159 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - krb5/libk5crypto3@1.18.3-6 + krb5/libk5crypto3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 adduser@3.118ubuntu5 - shadow/passwd@1:4.8.1-1ubuntu9 + shadow/passwd@1:4.8.1-2ubuntu2.1 - pam/libpam-modules@1.3.1-5ubuntu11 + pam/libpam-modules@1.4.0-11ubuntu2.4 - libnsl/libnsl2@1.3.0-2build1 + libnsl/libnsl2@1.3.0-2build2 - libtirpc/libtirpc3@1.3.2-2 + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - krb5/libgssapi-krb5-2@1.18.3-6 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 - krb5/libk5crypto3@1.18.3-6 + krb5/libk5crypto3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 adduser@3.118ubuntu5 - shadow/passwd@1:4.8.1-1ubuntu9 + shadow/passwd@1:4.8.1-2ubuntu2.1 - pam/libpam-modules@1.3.1-5ubuntu11 + pam/libpam-modules@1.4.0-11ubuntu2.4 - libnsl/libnsl2@1.3.0-2build1 + libnsl/libnsl2@1.3.0-2build2 - libtirpc/libtirpc3@1.3.2-2 + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - krb5/libgssapi-krb5-2@1.18.3-6 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 - krb5/libkrb5-3@1.18.3-6 + krb5/libkrb5-3@1.19.2-2ubuntu0.3 - krb5/libk5crypto3@1.18.3-6 + krb5/libk5crypto3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - krb5/libkrb5-3@1.18.3-6 + krb5/libkrb5-3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 adduser@3.118ubuntu5 - shadow/passwd@1:4.8.1-1ubuntu9 + shadow/passwd@1:4.8.1-2ubuntu2.1 - pam/libpam-modules@1.3.1-5ubuntu11 + pam/libpam-modules@1.4.0-11ubuntu2.4 - libnsl/libnsl2@1.3.0-2build1 + libnsl/libnsl2@1.3.0-2build2 - libtirpc/libtirpc3@1.3.2-2 + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - krb5/libgssapi-krb5-2@1.18.3-6 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 - krb5/libkrb5-3@1.18.3-6 + krb5/libkrb5-3@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - krb5/libgssapi-krb5-2@1.18.3-6 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - openssh/openssh-client@1:8.4p1-6ubuntu2.1 + openssh/openssh-client@1:8.9p1-3ubuntu0.6 - krb5/libgssapi-krb5-2@1.18.3-6 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git@1:2.32.0-1ubuntu1 + git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - krb5/libgssapi-krb5-2@1.18.3-6 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git@1:2.32.0-1ubuntu1 + git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 - libssh/libssh-4@0.9.6-1 + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 - krb5/libgssapi-krb5-2@1.18.3-6 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 adduser@3.118ubuntu5 - shadow/passwd@1:4.8.1-1ubuntu9 + shadow/passwd@1:4.8.1-2ubuntu2.1 - pam/libpam-modules@1.3.1-5ubuntu11 + pam/libpam-modules@1.4.0-11ubuntu2.4 - libnsl/libnsl2@1.3.0-2build1 + libnsl/libnsl2@1.3.0-2build2 - libtirpc/libtirpc3@1.3.2-2 + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - krb5/libgssapi-krb5-2@1.18.3-6 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - meta-common-packages@meta - - krb5/libkrb5support0@1.18.3-6 + krb5/libkrb5support0@1.19.2-2ubuntu0.3 @@ -7035,28 +5348,30 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream krb5 package.

      +

      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.

      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:21.10 krb5.

      +

      There is no fixed version for Ubuntu:22.04 krb5.

      References


    -

    Integer Overflow or Wraparound

    +

    Out-of-bounds Write

    @@ -7067,17 +5382,20 @@

    Integer Overflow or Wraparound

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - gmp/libgmp10 + gnupg2/gpgv
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and gmp/libgmp10@2:6.2.1+dfsg-1ubuntu2 + docker-image|quay.io/argoproj/argocd@v2.7.17 and gnupg2/gpgv@2.2.27-3ubuntu2.1
    @@ -7090,227 +5408,313 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - gmp/libgmp10@2:6.2.1+dfsg-1ubuntu2 + gnupg2/gpgv@2.2.27-3ubuntu2.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - coreutils@8.32-4ubuntu2 + apt@2.4.11 - gmp/libgmp10@2:6.2.1+dfsg-1ubuntu2 + gnupg2/gpgv@2.2.27-3ubuntu2.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - apt@2.3.9 + docker-image|quay.io/argoproj/argocd@v2.7.17 - gnutls28/libgnutls30@3.7.1-5ubuntu1 + gnupg2/gnupg@2.2.27-3ubuntu2.1 - gmp/libgmp10@2:6.2.1+dfsg-1ubuntu2 + gnupg2/gpgv@2.2.27-3ubuntu2.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - apt@2.3.9 + gnupg2/dirmngr@2.2.27-3ubuntu2.1 - gnutls28/libgnutls30@3.7.1-5ubuntu1 + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 - nettle/libhogweed6@3.7.3-1 + gnupg2/gpg@2.2.27-3ubuntu2.1 - gmp/libgmp10@2:6.2.1+dfsg-1ubuntu2 + gnupg2/gpgconf@2.2.27-3ubuntu2.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git@1:2.32.0-1ubuntu1 + gnupg2/gnupg@2.2.27-3ubuntu2.1 - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 - rtmpdump/librtmp1@2.4+20151223.gitfa8646d.1-2build3 - - gmp/libgmp10@2:6.2.1+dfsg-1ubuntu2 + gnupg2/gpgconf@2.2.27-3ubuntu2.1
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream gmp package.

    -

    GNU Multiple Precision Arithmetic Library (GMP) through 6.2.1 has an mpz/inp_raw.c integer overflow and resultant buffer overflow via crafted input, leading to a segmentation fault on 32-bit platforms.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:21.10 gmp.

    -

    References

    - - -
    - - +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpgsm@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + -
  • -
    -

    Buffer Overflow

    -
    + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + -
    - low severity -
    +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + -
    +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 + + - glibc/libc-bin -
    • + +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 + + -
    • Introduced through: +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 + + - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and glibc/libc-bin@2.34-0ubuntu3 +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 + + -
    • -
    +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + -
    +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + -

    Detailed paths

    +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + 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-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - glibc/libc-bin@2.34-0ubuntu3 + gnupg2/gpg-agent@2.2.27-3ubuntu2.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - meta-common-packages@meta + gnupg2/gnupg@2.2.27-3ubuntu2.1 - glibc/libc6@2.34-0ubuntu3 + gnupg2/gpg-agent@2.2.27-3ubuntu2.1
    • -
    - -
  • - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream glibc package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    The deprecated compatibility function clnt_create in the sunrpc module of the GNU C Library (aka glibc) through 2.34 copies its hostname argument on the stack without validating its length, which may result in a buffer overflow, potentially resulting in a denial of service or (if an application is not built with a stack protector enabled) arbitrary code execution.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 glibc to version 2.34-0ubuntu3.2 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Buffer Overflow

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - glibc/libc-bin -
    • - -
    • Introduced through: +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and glibc/libc-bin@2.34-0ubuntu3 +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + 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.7.17 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + -
    +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + 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.7.17 + + gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 + + -

    Detailed paths

    +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 + + -
      +
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - glibc/libc-bin@2.34-0ubuntu3 + gnupg2/gpgsm@2.2.27-3ubuntu2.1
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 - meta-common-packages@meta + gnupg2/gpgsm@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 - glibc/libc6@2.34-0ubuntu3 + gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -7322,24 +5726,26 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream glibc package. - See How to fix? for Ubuntu:21.10 relevant versions.

      -

      The deprecated compatibility function svcunix_create in the sunrpc module of the GNU C Library (aka glibc) through 2.34 copies its path argument on the stack without validating its length, which may result in a buffer overflow, potentially resulting in a denial of service or (if an application is not built with a stack protector enabled) arbitrary code execution.

      +

      Note: Versions mentioned in the description apply only to the upstream gnupg2 package and not the gnupg2 package as distributed by Ubuntu. + 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

      -

      Upgrade Ubuntu:21.10 glibc to version 2.34-0ubuntu3.2 or higher.

      +

      There is no fixed version for Ubuntu:22.04 gnupg2.

      References


  • @@ -7355,7 +5761,10 @@

    Allocation of Resources Without Limits or Throttling

  • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
  • +
  • + Package Manager: ubuntu:22.04
  • Vulnerable module: @@ -7365,7 +5774,7 @@

    Allocation of Resources Without Limits or Throttling

    Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and glibc/libc-bin@2.34-0ubuntu3 + docker-image|quay.io/argoproj/argocd@v2.7.17 and glibc/libc-bin@2.35-0ubuntu3.6
  • @@ -7378,20 +5787,18 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - glibc/libc-bin@2.34-0ubuntu3 + glibc/libc-bin@2.35-0ubuntu3.6
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - meta-common-packages@meta - - glibc/libc6@2.34-0ubuntu3 + glibc/libc6@2.35-0ubuntu3.6 @@ -7403,22 +5810,23 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream glibc package.

      +

      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.

      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:21.10 glibc.

      +

      There is no fixed version for Ubuntu:22.04 glibc.

      References


    @@ -7434,7 +5842,10 @@

    Improper Input Validation

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: @@ -7445,7 +5856,7 @@

      Improper Input Validation

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others + docker-image|quay.io/argoproj/argocd@v2.7.17, git@1:2.34.1-1ubuntu1.10 and others
    @@ -7457,31 +5868,31 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git@1:2.32.0-1ubuntu1 + git@1:2.34.1-1ubuntu1.10 - git/git-man@1:2.32.0-1ubuntu1 + git/git-man@1:2.34.1-1ubuntu1.10
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git@1:2.32.0-1ubuntu1 + git@1:2.34.1-1ubuntu1.10
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git-lfs@2.13.2-1 + git-lfs@3.0.2-1ubuntu0.2 - git@1:2.32.0-1ubuntu1 + git@1:2.34.1-1ubuntu1.10 @@ -7493,10 +5904,11 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream git package.

      +

      Note: Versions mentioned in the description apply only to the upstream git package and not the git package as distributed by Ubuntu. + 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:21.10 git.

      +

      There is no fixed version for Ubuntu:22.04 git.

      References

    -

    Incorrect Calculation

    +

    Uncontrolled Recursion

    @@ -7523,18 +5935,21 @@

    Incorrect Calculation

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: - expat/libexpat1 + gcc-12/libstdc++6
    • Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.17 and gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others
    @@ -7546,235 +5961,51 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 - - git@1:2.32.0-1ubuntu1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - expat/libexpat1@2.4.1-2 + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream expat package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    In Expat (aka libexpat) before 2.4.3, a left shift by 29 (or more) places in the storeAtts function in xmlparse.c can lead to realloc misbehavior (e.g., allocating too few bytes, or only freeing memory).

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 expat to version 2.4.1-2ubuntu0.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    CVE-2022-27775

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - curl/libcurl3-gnutls -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git@1:2.32.0-1ubuntu1 + apt@2.4.11 - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream curl package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    An information disclosure vulnerability exists in curl 7.65.0 to 7.82.0 are vulnerable that by using an IPv6 address that was in the connection pool but with a different zone id it could reuse a connection instead.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 curl to version 7.74.0-1.3ubuntu2.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Insufficiently Protected Credentials

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - curl/libcurl3-gnutls -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - git@1:2.32.0-1ubuntu1 + apt@2.4.11 - curl/libcurl3-gnutls@7.74.0-1.3ubuntu2 + apt/libapt-pkg6.0@2.4.11 + + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply to the upstream curl package. - See How to fix? for Ubuntu:21.10 relevant versions.

    -

    A insufficiently protected credentials vulnerability in fixed in curl 7.83.0 might leak authentication or cookie header data on HTTP redirects to the same host but another port number.

    -

    Remediation

    -

    Upgrade Ubuntu:21.10 curl to version 7.74.0-1.3ubuntu2.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Loop with Unreachable Exit Condition ('Infinite Loop')

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:21.10 -
    • -
    • - Vulnerable module: - - curl/libcurl3-gnutls -
    • - -
    • Introduced through: - - - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1, git@1:2.32.0-1ubuntu1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
    @@ -7820,7 +6050,10 @@

    Improper Input Validation

    • - Package Manager: ubuntu:21.10 + Manifest file: quay.io/argoproj/argocd:v2.7.17/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04
    • Vulnerable module: @@ -7830,7 +6063,7 @@

      Improper Input Validation

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 and coreutils@8.32-4ubuntu2 + docker-image|quay.io/argoproj/argocd@v2.7.17 and coreutils@8.32-4.1ubuntu1
    @@ -7843,9 +6076,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd-applicationset@v0.4.1 + docker-image|quay.io/argoproj/argocd@v2.7.17 - coreutils@8.32-4ubuntu2 + coreutils@8.32-4.1ubuntu1 @@ -7857,10 +6090,11 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply to the upstream coreutils package.

      +

      Note: Versions mentioned in the description apply only to the upstream coreutils package and not the coreutils package as distributed by Ubuntu. + 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:21.10 coreutils.

      +

      There is no fixed version for Ubuntu:22.04 coreutils.

      References


    diff --git a/docs/snyk/v2.7.17/redis_7.0.14-alpine.html b/docs/snyk/v2.7.17/redis_7.0.14-alpine.html new file mode 100644 index 0000000000000..ea9cd5f9152fd --- /dev/null +++ b/docs/snyk/v2.7.17/redis_7.0.14-alpine.html @@ -0,0 +1,993 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    March 24th 2024, 12:22:21 am (UTC+00:00)

    +
    +
    + Scanned the following paths: +
      +
    • redis:7.0.14-alpine (apk)
    • +
    • redis:7.0.14-alpine/tianon/gosu//usr/local/bin/gosu (gomodules)
    • +
    +
    + +
    +
    3 known vulnerabilities
    +
    27 vulnerable dependency paths
    +
    19 dependencies
    +
    +
    +
    +
    + +
    +
    +
    +

    Out-of-bounds Write

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.19 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.14-alpine and openssl/libcrypto3@3.1.4-r2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + busybox/ssl_client@1.36.1-r15 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libssl3@3.1.4-r2 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + busybox/ssl_client@1.36.1-r15 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    + +
    + +
    + +

    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.19 relevant fixed versions and status.

    +

    Issue summary: The POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

    +

    Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

    +

    The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

    +

    The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

    +

    The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

    +

    Remediation

    +

    Upgrade Alpine:3.19 openssl to version 3.1.4-r3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-0727

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.19 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.14-alpine and openssl/libcrypto3@3.1.4-r2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + busybox/ssl_client@1.36.1-r15 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libssl3@3.1.4-r2 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + busybox/ssl_client@1.36.1-r15 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    + +
    + +
    + +

    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.19 relevant fixed versions and status.

    +

    Issue summary: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

    +

    Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

    +

    A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

    +

    OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

    +

    We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

    +

    The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.19 openssl to version 3.1.4-r5 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-6237

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.19 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.14-alpine and openssl/libcrypto3@3.1.4-r2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + busybox/ssl_client@1.36.1-r15 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libssl3@3.1.4-r2 + + openssl/libcrypto3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + .redis-rundeps@20231208.201137 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + apk-tools/apk-tools@2.14.0-r5 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.14-alpine + + busybox/ssl_client@1.36.1-r15 + + openssl/libssl3@3.1.4-r2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    This vulnerability has not been analyzed by NVD yet.

    +

    Remediation

    +

    Upgrade Alpine:3.19 openssl to version 3.1.4-r4 or higher.

    + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.4.19/argocd-iac-install.html b/docs/snyk/v2.8.13/argocd-iac-install.html similarity index 73% rename from docs/snyk/v2.4.19/argocd-iac-install.html rename to docs/snyk/v2.8.13/argocd-iac-install.html index 0b3265dde5efc..8e0c8abdd40c3 100644 --- a/docs/snyk/v2.4.19/argocd-iac-install.html +++ b/docs/snyk/v2.8.13/argocd-iac-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    January 22nd 2023, 12:22:53 am

    +

    March 24th 2024, 12:21:30 am (UTC+00:00)

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

    Snyk test report

    -
    32 total issues
    +
    38 total issues
    @@ -483,7 +483,7 @@

    Snyk test report

    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -494,7 +494,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -507,29 +507,29 @@

      Role with dangerous permissions

    • - Line number: 9063 + Line number: 18466

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -540,7 +540,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -553,29 +553,29 @@

      Role with dangerous permissions

    • - Line number: 9140 + Line number: 18543

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -586,7 +586,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -599,29 +599,29 @@

      Role with dangerous permissions

    • - Line number: 9168 + Line number: 18571

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -632,42 +632,42 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: [DocId: 13] - rules[3] + rules[1] resources
    • - Line number: 9212 + Line number: 18601

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -678,42 +678,42 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: [DocId: 13] - rules[1] + rules[3] resources
    • - Line number: 9194 + Line number: 18619

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -724,7 +724,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -737,24 +737,24 @@

      Role with dangerous permissions

    • - Line number: 9228 + Line number: 18635

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    @@ -770,11 +770,11 @@

    Container could be running with outdated image

    • - Public ID: SNYK-CC-K8S-42 + Public ID: SNYK-CC-K8S-42
    • Introduced through: - [DocId: 46] + [DocId: 45] spec @@ -789,7 +789,7 @@

      Container could be running with outdated image

    • - Line number: 10100 + Line number: 19761
    @@ -806,7 +806,7 @@

    Remediation

    @@ -822,11 +822,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 42] + [DocId: 41] input @@ -847,7 +847,7 @@

      Container has no CPU limit

    • - Line number: 9686 + Line number: 19118
    @@ -864,7 +864,7 @@

    Remediation

    @@ -880,11 +880,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 43] + [DocId: 42] input @@ -905,7 +905,7 @@

      Container has no CPU limit

    • - Line number: 9786 + Line number: 19351
    @@ -922,7 +922,7 @@

    Remediation

    @@ -938,11 +938,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 43] + [DocId: 42] input @@ -963,7 +963,7 @@

      Container has no CPU limit

    • - Line number: 9763 + Line number: 19317
    @@ -980,7 +980,7 @@

    Remediation

    @@ -996,11 +996,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 44] + [DocId: 43] input @@ -1021,7 +1021,7 @@

      Container has no CPU limit

    • - Line number: 9829 + Line number: 19411
    @@ -1038,7 +1038,7 @@

    Remediation

    @@ -1054,11 +1054,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 45] + [DocId: 44] input @@ -1079,7 +1079,7 @@

      Container has no CPU limit

    • - Line number: 9901 + Line number: 19504
    @@ -1096,7 +1096,7 @@

    Remediation

    @@ -1112,11 +1112,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 46] + [DocId: 45] input @@ -1137,7 +1137,7 @@

      Container has no CPU limit

    • - Line number: 10100 + Line number: 19761
    @@ -1154,7 +1154,7 @@

    Remediation

    @@ -1170,11 +1170,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 46] + [DocId: 45] input @@ -1195,7 +1195,7 @@

      Container has no CPU limit

    • - Line number: 9955 + Line number: 19561
    @@ -1212,7 +1212,7 @@

    Remediation

    @@ -1228,11 +1228,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 47] + [DocId: 46] input @@ -1253,7 +1253,7 @@

      Container has no CPU limit

    • - Line number: 10183 + Line number: 19846
    @@ -1270,7 +1270,7 @@

    Remediation

    @@ -1286,11 +1286,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 48] + [DocId: 47] input @@ -1311,7 +1311,7 @@

      Container has no CPU limit

    • - Line number: 10443 + Line number: 20168
    @@ -1328,7 +1328,7 @@

    Remediation

    @@ -1344,11 +1344,11 @@

    Container is running with multiple open ports

    • - Public ID: SNYK-CC-K8S-36 + Public ID: SNYK-CC-K8S-36
    • Introduced through: - [DocId: 43] + [DocId: 42] spec @@ -1363,7 +1363,7 @@

      Container is running with multiple open ports

    • - Line number: 9770 + Line number: 19331
    @@ -1380,12 +1380,12 @@

    Remediation

    -

    Container is running with writable root filesystem

    +

    Container is running without liveness probe

    @@ -1396,13 +1396,11 @@

    Container is running with writable root filesystem

    • - Public ID: SNYK-CC-K8S-8 + Public ID: SNYK-CC-K8S-41
    • Introduced through: - [DocId: 45] - - input + [DocId: 41] spec @@ -1410,33 +1408,31 @@

      Container is running with writable root filesystem

      spec - containers[redis] - - securityContext + containers[argocd-applicationset-controller] - readOnlyRootFilesystem + livenessProbe
    • - Line number: 9911 + Line number: 19118

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    +

    Add `livenessProbe` attribute


    @@ -1452,7 +1448,7 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: @@ -1464,14 +1460,14 @@

      Container is running without liveness probe

      spec - containers[argocd-applicationset-controller] + containers[dex] livenessProbe
    • - Line number: 9686 + Line number: 19317
    @@ -1488,7 +1484,7 @@

    Remediation

    @@ -1504,11 +1500,11 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: - [DocId: 43] + [DocId: 44] spec @@ -1516,14 +1512,14 @@

      Container is running without liveness probe

      spec - containers[dex] + containers[redis] livenessProbe
    • - Line number: 9763 + Line number: 19504
    @@ -1540,12 +1536,12 @@

    Remediation

    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1556,11 +1552,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 43] + [DocId: 41] + + input spec @@ -1568,36 +1566,40 @@

      Container is running without liveness probe

      spec - initContainers[copyutil] + containers[argocd-applicationset-controller] - livenessProbe + resources + + limits + + memory
    • - Line number: 9786 + Line number: 19118

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1608,11 +1610,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 45] + [DocId: 42] + + input spec @@ -1620,36 +1624,40 @@

      Container is running without liveness probe

      spec - containers[redis] + containers[dex] - livenessProbe + resources + + limits + + memory
    • - Line number: 9901 + Line number: 19317

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1660,11 +1668,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 46] + [DocId: 42] + + input spec @@ -1674,29 +1684,33 @@

      Container is running without liveness probe

      initContainers[copyutil] - livenessProbe + resources + + limits + + memory
    • - Line number: 10100 + Line number: 19351

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    @@ -1712,11 +1726,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 42] + [DocId: 43] input @@ -1726,7 +1740,7 @@

      Container is running without memory limit

      spec - containers[argocd-applicationset-controller] + containers[argocd-notifications-controller] resources @@ -1737,7 +1751,7 @@

      Container is running without memory limit

    • - Line number: 9686 + Line number: 19411
    @@ -1754,7 +1768,7 @@

    Remediation

    @@ -1770,11 +1784,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 43] + [DocId: 44] input @@ -1784,7 +1798,7 @@

      Container is running without memory limit

      spec - containers[dex] + containers[redis] resources @@ -1795,7 +1809,7 @@

      Container is running without memory limit

    • - Line number: 9763 + Line number: 19504
    @@ -1812,7 +1826,7 @@

    Remediation

    @@ -1828,11 +1842,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 43] + [DocId: 45] input @@ -1853,7 +1867,7 @@

      Container is running without memory limit

    • - Line number: 9786 + Line number: 19761
    @@ -1870,7 +1884,7 @@

    Remediation

    @@ -1886,11 +1900,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 44] + [DocId: 45] input @@ -1900,7 +1914,7 @@

      Container is running without memory limit

      spec - containers[argocd-notifications-controller] + containers[argocd-repo-server] resources @@ -1911,7 +1925,7 @@

      Container is running without memory limit

    • - Line number: 9829 + Line number: 19561
    @@ -1928,7 +1942,7 @@

    Remediation

    @@ -1944,11 +1958,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 45] + [DocId: 46] input @@ -1958,7 +1972,7 @@

      Container is running without memory limit

      spec - containers[redis] + containers[argocd-server] resources @@ -1969,7 +1983,7 @@

      Container is running without memory limit

    • - Line number: 9901 + Line number: 19846
    @@ -1986,7 +2000,7 @@

    Remediation

    @@ -2002,11 +2016,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 46] + [DocId: 47] input @@ -2016,7 +2030,7 @@

      Container is running without memory limit

      spec - initContainers[copyutil] + containers[argocd-application-controller] resources @@ -2027,7 +2041,7 @@

      Container is running without memory limit

    • - Line number: 10100 + Line number: 20168
    @@ -2044,12 +2058,12 @@

    Remediation

    -

    Container is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2060,11 +2074,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: - [DocId: 46] + [DocId: 41] input @@ -2074,40 +2088,94 @@

      Container is running without memory limit

      spec - containers[argocd-repo-server] + containers[argocd-applicationset-controller] - resources + securityContext - limits + runAsUser + +
    • + +
    • + Line number: 19241 +
    • +
    + +
    + +

    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] - memory + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser
    • - Line number: 9955 + Line number: 19359

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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 is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2118,11 +2186,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: - [DocId: 47] + [DocId: 42] input @@ -2132,40 +2200,94 @@

      Container is running without memory limit

      spec - containers[argocd-server] + containers[dex] - resources + securityContext - limits + runAsUser + +
    • + +
    • + Line number: 19334 +
    • +
    + +
    + +

    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] - memory + input + + spec + + template + + spec + + containers[argocd-notifications-controller] + + securityContext + + runAsUser
    • - Line number: 10183 + Line number: 19438

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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 is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2176,11 +2298,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: - [DocId: 48] + [DocId: 44] input @@ -2190,35 +2312,257 @@

      Container is running without memory limit

      spec - containers[argocd-application-controller] + containers[redis] - resources + securityContext - limits + runAsUser + +
    • + +
    • + Line number: 19514 +
    • +
    + +
    + +

    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] - memory + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser
    • - Line number: 10443 + Line number: 19768

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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: 19734 +
    • +
    + +
    + +

    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: 20078 +
    • +
    + +
    + +

    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: 20316 +
    • +
    + +
    + +

    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.6.0-rc4/argocd-iac-namespace-install.html b/docs/snyk/v2.8.13/argocd-iac-namespace-install.html similarity index 73% rename from docs/snyk/v2.6.0-rc4/argocd-iac-namespace-install.html rename to docs/snyk/v2.8.13/argocd-iac-namespace-install.html index 935671b03009d..17296cd003c37 100644 --- a/docs/snyk/v2.6.0-rc4/argocd-iac-namespace-install.html +++ b/docs/snyk/v2.8.13/argocd-iac-namespace-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    January 22nd 2023, 12:19:39 am

    +

    March 24th 2024, 12:21:38 am (UTC+00:00)

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

    Snyk test report

    -
    32 total issues
    +
    38 total issues
    @@ -483,7 +483,7 @@

    Snyk test report

    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -494,7 +494,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -514,22 +514,22 @@

      Role with dangerous permissions


      Impact

      -

      Using this role grants dangerous permissions

      +

      Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

      Remediation

      -

      Consider removing this permissions

      +

      Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -540,7 +540,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -560,22 +560,22 @@

      Role with dangerous permissions


      Impact

      -

      Using this role grants dangerous permissions

      +

      Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

      Remediation

      -

      Consider removing this permissions

      +

      Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -586,7 +586,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -606,22 +606,22 @@

      Role with dangerous permissions


      Impact

      -

      Using this role grants dangerous permissions

      +

      Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

      Remediation

      -

      Consider removing this permissions

      +

      Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -632,42 +632,42 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: [DocId: 10] - rules[3] + rules[1] resources
    • - Line number: 226 + Line number: 212

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -678,42 +678,42 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: [DocId: 10] - rules[1] + rules[3] resources
    • - Line number: 208 + Line number: 230

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -724,7 +724,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -737,24 +737,24 @@

      Role with dangerous permissions

    • - Line number: 242 + Line number: 246

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    @@ -770,11 +770,11 @@

    Container could be running with outdated image

    • - Public ID: SNYK-CC-K8S-42 + Public ID: SNYK-CC-K8S-42
    • Introduced through: - [DocId: 39] + [DocId: 38] spec @@ -789,7 +789,7 @@

      Container could be running with outdated image

    • - Line number: 1153 + Line number: 1267
    @@ -806,7 +806,7 @@

    Remediation

    @@ -822,11 +822,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 35] + [DocId: 34] input @@ -847,7 +847,7 @@

      Container has no CPU limit

    • - Line number: 616 + Line number: 624
    @@ -864,7 +864,7 @@

    Remediation

    @@ -880,11 +880,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 36] + [DocId: 35] input @@ -905,7 +905,7 @@

      Container has no CPU limit

    • - Line number: 789 + Line number: 857
    @@ -922,7 +922,7 @@

    Remediation

    @@ -938,11 +938,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 36] + [DocId: 35] input @@ -963,7 +963,7 @@

      Container has no CPU limit

    • - Line number: 755 + Line number: 823
    @@ -980,7 +980,7 @@

    Remediation

    @@ -996,11 +996,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 37] + [DocId: 36] input @@ -1021,7 +1021,7 @@

      Container has no CPU limit

    • - Line number: 845 + Line number: 917
    @@ -1038,7 +1038,7 @@

    Remediation

    @@ -1054,11 +1054,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 38] + [DocId: 37] input @@ -1079,7 +1079,7 @@

      Container has no CPU limit

    • - Line number: 919 + Line number: 1010
    @@ -1096,7 +1096,7 @@

    Remediation

    @@ -1112,11 +1112,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 39] + [DocId: 38] input @@ -1137,7 +1137,7 @@

      Container has no CPU limit

    • - Line number: 1153 + Line number: 1267
    @@ -1154,7 +1154,7 @@

    Remediation

    @@ -1170,11 +1170,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 39] + [DocId: 38] input @@ -1195,7 +1195,7 @@

      Container has no CPU limit

    • - Line number: 975 + Line number: 1067
    @@ -1212,7 +1212,7 @@

    Remediation

    @@ -1228,11 +1228,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 40] + [DocId: 39] input @@ -1253,7 +1253,7 @@

      Container has no CPU limit

    • - Line number: 1238 + Line number: 1352
    @@ -1270,7 +1270,7 @@

    Remediation

    @@ -1286,11 +1286,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 41] + [DocId: 40] input @@ -1311,7 +1311,7 @@

      Container has no CPU limit

    • - Line number: 1542 + Line number: 1674
    @@ -1328,7 +1328,7 @@

    Remediation

    @@ -1344,11 +1344,11 @@

    Container is running with multiple open ports

    • - Public ID: SNYK-CC-K8S-36 + Public ID: SNYK-CC-K8S-36
    • Introduced through: - [DocId: 36] + [DocId: 35] spec @@ -1363,7 +1363,7 @@

      Container is running with multiple open ports

    • - Line number: 769 + Line number: 837
    @@ -1380,12 +1380,12 @@

    Remediation

    -

    Container is running with writable root filesystem

    +

    Container is running without liveness probe

    @@ -1396,13 +1396,11 @@

    Container is running with writable root filesystem

    • - Public ID: SNYK-CC-K8S-8 + Public ID: SNYK-CC-K8S-41
    • Introduced through: - [DocId: 38] - - input + [DocId: 34] spec @@ -1410,33 +1408,31 @@

      Container is running with writable root filesystem

      spec - containers[redis] - - securityContext + containers[argocd-applicationset-controller] - readOnlyRootFilesystem + livenessProbe
    • - Line number: 929 + Line number: 624

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    +

    Add `livenessProbe` attribute


    @@ -1452,7 +1448,7 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: @@ -1464,14 +1460,14 @@

      Container is running without liveness probe

      spec - containers[argocd-applicationset-controller] + containers[dex] livenessProbe
    • - Line number: 616 + Line number: 823
    @@ -1488,7 +1484,7 @@

    Remediation

    @@ -1504,11 +1500,11 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: - [DocId: 36] + [DocId: 37] spec @@ -1516,14 +1512,14 @@

      Container is running without liveness probe

      spec - containers[dex] + containers[redis] livenessProbe
    • - Line number: 755 + Line number: 1010
    @@ -1540,12 +1536,12 @@

    Remediation

    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1556,11 +1552,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 36] + [DocId: 34] + + input spec @@ -1568,36 +1566,40 @@

      Container is running without liveness probe

      spec - initContainers[copyutil] + containers[argocd-applicationset-controller] - livenessProbe + resources + + limits + + memory
    • - Line number: 789 + Line number: 624

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1608,11 +1610,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 38] + [DocId: 35] + + input spec @@ -1620,36 +1624,40 @@

      Container is running without liveness probe

      spec - containers[redis] + containers[dex] - livenessProbe + resources + + limits + + memory
    • - Line number: 919 + Line number: 823

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1660,11 +1668,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 39] + [DocId: 35] + + input spec @@ -1674,29 +1684,33 @@

      Container is running without liveness probe

      initContainers[copyutil] - livenessProbe + resources + + limits + + memory
    • - Line number: 1153 + Line number: 857

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    @@ -1712,11 +1726,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 35] + [DocId: 36] input @@ -1726,7 +1740,7 @@

      Container is running without memory limit

      spec - containers[argocd-applicationset-controller] + containers[argocd-notifications-controller] resources @@ -1737,7 +1751,7 @@

      Container is running without memory limit

    • - Line number: 616 + Line number: 917
    @@ -1754,7 +1768,7 @@

    Remediation

    @@ -1770,11 +1784,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 36] + [DocId: 37] input @@ -1784,7 +1798,7 @@

      Container is running without memory limit

      spec - containers[dex] + containers[redis] resources @@ -1795,7 +1809,7 @@

      Container is running without memory limit

    • - Line number: 755 + Line number: 1010
    @@ -1812,7 +1826,7 @@

    Remediation

    @@ -1828,11 +1842,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 36] + [DocId: 38] input @@ -1853,7 +1867,7 @@

      Container is running without memory limit

    • - Line number: 789 + Line number: 1267
    @@ -1870,7 +1884,7 @@

    Remediation

    @@ -1886,11 +1900,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 37] + [DocId: 38] input @@ -1900,7 +1914,7 @@

      Container is running without memory limit

      spec - containers[argocd-notifications-controller] + containers[argocd-repo-server] resources @@ -1911,7 +1925,7 @@

      Container is running without memory limit

    • - Line number: 845 + Line number: 1067
    @@ -1928,7 +1942,7 @@

    Remediation

    @@ -1944,11 +1958,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 38] + [DocId: 39] input @@ -1958,7 +1972,7 @@

      Container is running without memory limit

      spec - containers[redis] + containers[argocd-server] resources @@ -1969,7 +1983,7 @@

      Container is running without memory limit

    • - Line number: 919 + Line number: 1352
    @@ -1986,7 +2000,7 @@

    Remediation

    @@ -2002,11 +2016,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 39] + [DocId: 40] input @@ -2016,7 +2030,7 @@

      Container is running without memory limit

      spec - initContainers[copyutil] + containers[argocd-application-controller] resources @@ -2027,7 +2041,7 @@

      Container is running without memory limit

    • - Line number: 1153 + Line number: 1674
    @@ -2044,12 +2058,12 @@

    Remediation

    -

    Container is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2060,11 +2074,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: - [DocId: 39] + [DocId: 34] input @@ -2074,40 +2088,94 @@

      Container is running without memory limit

      spec - containers[argocd-repo-server] + containers[argocd-applicationset-controller] - resources + securityContext - limits + runAsUser + +
    • + +
    • + Line number: 747 +
    • +
    + +
    + +

    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] - memory + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser
    • - Line number: 975 + Line number: 865

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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 is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2118,11 +2186,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: - [DocId: 40] + [DocId: 35] input @@ -2132,40 +2200,94 @@

      Container is running without memory limit

      spec - containers[argocd-server] + containers[dex] - resources + securityContext - limits + runAsUser + +
    • + +
    • + Line number: 840 +
    • +
    + +
    + +

    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] - memory + input + + spec + + template + + spec + + containers[argocd-notifications-controller] + + securityContext + + runAsUser
    • - Line number: 1238 + Line number: 944

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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 is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2176,11 +2298,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: - [DocId: 41] + [DocId: 37] input @@ -2190,35 +2312,257 @@

      Container is running without memory limit

      spec - containers[argocd-application-controller] + containers[redis] - resources + securityContext - limits + runAsUser + +
    • + +
    • + Line number: 1020 +
    • +
    + +
    + +

    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] - memory + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser
    • - Line number: 1542 + Line number: 1274

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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: 1240 +
    • +
    + +
    + +

    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: 1584 +
    • +
    + +
    + +

    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: 1822 +
    • +
    + +
    + +

    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.5.7/argocd-test.html b/docs/snyk/v2.8.13/argocd-test.html similarity index 54% rename from docs/snyk/v2.5.7/argocd-test.html rename to docs/snyk/v2.8.13/argocd-test.html index 98e81d5448610..8f02f01423f2f 100644 --- a/docs/snyk/v2.5.7/argocd-test.html +++ b/docs/snyk/v2.8.13/argocd-test.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,19 +456,20 @@

    Snyk test report

    -

    January 22nd 2023, 12:19:59 am

    +

    March 24th 2024, 12:19:50 am (UTC+00:00)

    Scanned the following paths:
      -
    • /argo-cd/argoproj/argo-cd/v2 (gomodules)
    • /argo-cd (yarn)
    • +
    • /argo-cd/argoproj/argo-cd/v2/go.mod (gomodules)
    • +
    • /argo-cd/ui/yarn.lock (yarn)
    -
    8 known vulnerabilities
    -
    130 vulnerable dependency paths
    -
    1720 dependencies
    +
    12 known vulnerabilities
    +
    108 vulnerable dependency paths
    +
    1856 dependencies
    @@ -476,112 +477,33 @@

    Snyk test report

    -
    -

    Server-side Request Forgery (SSRF)

    +
    +

    Denial of Service (DoS)

    -
    - medium severity +
    + high severity

    • - Package Manager: npm -
    • -
    • - Vulnerable module: - - parse-url + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod
    • - -
    • Introduced through: - - - argo-cd-ui@1.0.0, git-url-parse@11.6.0 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - argo-cd-ui@1.0.0 - - git-url-parse@11.6.0 - - git-up@4.0.5 - - parse-url@6.0.5 - - - -
    • -
    - -
    - -
    - -

    Overview

    -

    parse-url is an An advanced url parser supporting git urls too.

    -

    Affected versions of this package are vulnerable to Server-side Request Forgery (SSRF) due to improper detection of protocol, resource, and pathname fields. Exploiting this vulnerability results in bypassing protocol verification.

    -

    PoC:

    -
    import parseUrl from "parse-url";
    -        import fetch from 'node-fetch';
    -        var parsed=parseUrl("http://nnnn@localhost:808:/?id=xss")
    -        if(parsed.resource=="localhost"){
    -        console.log("internal network access is blocked")
    -        }
    -        else{
    -           const response = await fetch('http://'+parsed.resource+parsed.pathname);
    -                console.log(response)
    -         }
    -        
    -

    Remediation

    -

    Upgrade parse-url to version 8.1.0 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Improper Input Validation

    -
    - -
    - medium severity -
    - -
    - -
    • - Package Manager: npm + Package Manager: golang
    • Vulnerable module: - parse-url + github.com/go-jose/go-jose/v3
    • Introduced through: - argo-cd-ui@1.0.0, git-url-parse@11.6.0 and others + github.com/argoproj/argo-cd/v2@0.0.0, github.com/coreos/go-oidc/v3/oidc@3.6.0 and others
    @@ -593,13 +515,11 @@

    Detailed paths

    • Introduced through: - argo-cd-ui@1.0.0 - - git-url-parse@11.6.0 + github.com/argoproj/argo-cd/v2@0.0.0 - git-up@4.0.5 + github.com/coreos/go-oidc/v3/oidc@3.6.0 - parse-url@6.0.5 + github.com/go-jose/go-jose/v3@3.0.0 @@ -611,49 +531,36 @@

      Detailed paths


      Overview

      -

      parse-url is an An advanced url parser supporting git urls too.

      -

      Affected versions of this package are vulnerable to Improper Input Validation due to incorrect parsing of URLs. This allows the attacker to craft a malformed URL which can lead to a phishing attack.

      -
      
      -        const parseUrl = require("parse-url");
      -        const Url = require("url");
      -        
      -        const express = require('express');
      -        const app = express();
      -        
      -        var url = "https://www.google.com:x@fakesite.com:x";
      -        parsed = parseUrl(url);
      -        console.log("[*]`parse-url` output: ")
      -        console.log(parsed);
      -        
      -        parsed2 = Url.parse(url);
      -        console.log("[*]`url` output: ")
      -        console.log(parsed2)
      -        
      -        app.get('/', (req, res) => {
      -            if (parsed.host == "www.google.com") {
      -                res.send("<a href=\'" + parsed2.href + "\'>CLICK ME!</a>")
      -            }
      -        })
      -        
      -        app.listen(8888,"0.0.0.0");
      -        
      +

      Affected versions of this package are vulnerable to Denial of Service (DoS) when decrypting JWE inputs. An attacker can cause a denial-of-service by providing a PBES2 encrypted JWE blob with a very large p2c value.

      +

      Details

      +

      Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

      +

      Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

      +

      One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

      +

      When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

      +

      Two common types of DoS vulnerabilities:

      +
        +
      • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

        +
      • +
      • Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

        +
      • +

      Remediation

      -

      Upgrade parse-url to version 8.1.0 or higher.

      +

      Upgrade github.com/go-jose/go-jose/v3 to version 3.0.1 or higher.

      References


    -

    Regular Expression Denial of Service (ReDoS)

    +

    LGPL-3.0 license

    @@ -664,18 +571,21 @@

    Regular Expression Denial of Service (ReDoS)

    • - Package Manager: npm + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod
    • - Vulnerable module: + Package Manager: golang +
    • +
    • + Module: - minimatch + gopkg.in/retry.v1
    • Introduced through: - argo-cd-ui@1.0.0, redoc@2.0.0-rc.64 and others + github.com/argoproj/argo-cd/v2@0.0.0, github.com/Azure/kubelogin/pkg/token@0.0.20 and others
    @@ -687,13 +597,11 @@

    Detailed paths

    • Introduced through: - argo-cd-ui@1.0.0 - - redoc@2.0.0-rc.64 + github.com/argoproj/argo-cd/v2@0.0.0 - @redocly/openapi-core@1.0.0-beta.82 + github.com/Azure/kubelogin/pkg/token@0.0.20 - minimatch@3.0.4 + gopkg.in/retry.v1@1.0.3 @@ -704,86 +612,17 @@

      Detailed paths


      -

      Overview

      -

      minimatch is a minimal matching utility.

      -

      Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) via the braceExpand function in minimatch.js.

      -

      Details

      -

      Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.

      -

      The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.

      -

      Let’s take the following regular expression as an example:

      -
      regex = /A(B|C+)+D/
      -        
      -

      This regular expression accomplishes the following:

      -
        -
      • A The string must start with the letter 'A'
      • -
      • (B|C+)+ The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the + matches one or more times). The + at the end of this section states that we can look for one or more matches of this section.
      • -
      • D Finally, we ensure this section of the string ends with a 'D'
      • -
      -

      The expression would match inputs such as ABBD, ABCCCCD, ABCBCCCD and ACCCCCD

      -

      It most cases, it doesn't take very long for a regex engine to find a match:

      -
      $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
      -        0.04s user 0.01s system 95% cpu 0.052 total
      -        
      -        $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
      -        1.79s user 0.02s system 99% cpu 1.812 total
      -        
      -

      The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.

      -

      Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.

      -

      Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:

      -
        -
      1. CCC
      2. -
      3. CC+C
      4. -
      5. C+CC
      6. -
      7. C+C+C.
      8. -
      -

      The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.

      -

      From there, the number of steps the engine must use to validate a string just continues to grow.

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      StringNumber of C'sNumber of steps
      ACCCX338
      ACCCCX471
      ACCCCCX5136
      ACCCCCCCCCCCCCCX1465,553
      -

      By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.

      -

      Remediation

      -

      Upgrade minimatch to version 3.0.5 or higher.

      -

      References

      - +

      LGPL-3.0 license


    -

    Denial of Service (DoS)

    +

    Infinite loop

    @@ -793,19 +632,22 @@

    Denial of Service (DoS)


      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • Package Manager: golang
    • Vulnerable module: - golang.org/x/net/http2 + google.golang.org/protobuf/internal/encoding/json
    • Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0, k8s.io/client-go/rest@0.24.2 and others + github.com/argoproj/argo-cd/v2@0.0.0, github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 and others
    @@ -819,20 +661,13 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/rest@0.24.2 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - golang.org/x/net/http2@#9d032be2e588 - - - - -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + github.com/golang/protobuf/jsonpb@1.4.2 - github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -841,20 +676,15 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/argoproj/pkg/grpc/http@#d56162821bd1 - golang.org/x/net/http2@#9d032be2e588 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - github.com/soheilhy/cmux@0.1.5 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -863,11 +693,15 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/cache@0.24.2 + google.golang.org/grpc@1.58.3 + + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -876,24 +710,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/discovery@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc@1.58.3 - golang.org/x/net/http2@#9d032be2e588 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/dynamic@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -902,24 +729,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/transport/spdy@0.24.2 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc@1.58.3 - golang.org/x/net/http2@#9d032be2e588 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + google.golang.org/grpc/internal/transport@1.58.3 - github.com/argoproj/pkg/kubeclientmetrics@#36c59d8fafe0 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -928,24 +748,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/testing@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc@1.58.3 - golang.org/x/net/http2@#9d032be2e588 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/kubernetes@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -954,24 +767,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/azure@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc@1.58.3 - golang.org/x/net/http2@#9d032be2e588 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/plugin/pkg/client/auth/gcp@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -980,24 +786,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/oidc@0.24.2 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc@1.58.3 - golang.org/x/net/http2@#9d032be2e588 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/tools/record@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1006,24 +805,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/watch@0.24.2 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 + google.golang.org/grpc@1.58.3 - golang.org/x/net/http2@#9d032be2e588 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/pretty@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1032,13 +824,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/kubectl/pkg/util/openapi@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 - k8s.io/client-go/discovery@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1047,13 +843,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/listers/core/v1@0.24.2 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.42.0 + + google.golang.org/grpc@1.58.3 + + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/tools/cache@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1062,13 +862,19 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/api@#4d8552b0775f + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 - k8s.io/client-go/tools/cache@0.24.2 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/transport@1.58.3 + + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1077,13 +883,19 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/informers/core/v1@0.24.2 + google.golang.org/grpc/reflection@1.58.3 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.58.3 - k8s.io/client-go/tools/cache@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1092,13 +904,19 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/informers@0.24.2 + google.golang.org/grpc/health@1.58.3 + + google.golang.org/grpc/health/grpc_health_v1@1.58.3 + + google.golang.org/grpc@1.58.3 - k8s.io/client-go/tools/cache@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1107,43 +925,98 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/clientcmd@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 - k8s.io/client-go/tools/auth@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 - k8s.io/client-go/rest@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - golang.org/x/net/http2@#9d032be2e588 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - github.com/argoproj/notifications-engine/pkg/controller@#4d8552b0775f + google.golang.org/grpc@1.58.3 - k8s.io/client-go/tools/cache@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0
  • + + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/internal/encoding/json to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Stack-based Buffer Overflow

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
    • 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 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/client-go/rest@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1152,13 +1025,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/kubernetes/fake@0.24.2 + github.com/argoproj/pkg/grpc/http@#d56162821bd1 - k8s.io/client-go/testing@0.24.2 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/client-go/rest@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1167,13 +1040,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/remotecommand@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/transport/spdy@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1182,13 +1055,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - k8s.io/apimachinery/pkg/watch@0.24.2 + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.7.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1197,13 +1070,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/rest@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - k8s.io/client-go/transport@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1212,13 +1087,15 @@

      Detailed paths

      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/health/grpc_health_v1@1.58.3 + + google.golang.org/grpc@1.58.3 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1227,13 +1104,15 @@

      Detailed paths

      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/auth@1.4.0 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1242,13 +1121,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/grpc-ecosystem/go-grpc-middleware/retry@1.3.0 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 + + google.golang.org/grpc@1.58.3 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1259,11 +1140,13 @@

      Detailed paths

      github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1272,13 +1155,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - google.golang.org/grpc/health/grpc_health_v1@1.45.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 + + google.golang.org/grpc@1.58.3 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1287,13 +1172,15 @@

      Detailed paths

      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@1.4.0 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1302,13 +1189,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.42.0 + + google.golang.org/grpc@1.58.3 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1317,13 +1206,15 @@

      Detailed paths

      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.58.3 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1332,13 +1223,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.6.3 + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 + + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1347,15 +1242,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/cache@#98ccd3d43fd9 + google.golang.org/grpc/reflection@1.58.3 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.58.3 - k8s.io/kubectl/pkg/util/openapi@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/discovery@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1364,15 +1261,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync@#98ccd3d43fd9 + google.golang.org/grpc/health@1.58.3 - k8s.io/kubectl/pkg/util/openapi@0.24.2 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/client-go/discovery@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1381,15 +1280,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/utils/kube@#98ccd3d43fd9 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 + + google.golang.org/grpc@1.58.3 - k8s.io/kubectl/pkg/util/openapi@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/discovery@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1398,15 +1299,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/cmd@#4d8552b0775f + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/client-go/tools/clientcmd@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/tools/auth@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1415,15 +1318,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/kubectl/pkg/util/term@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 + + google.golang.org/grpc@1.58.3 - k8s.io/client-go/tools/remotecommand@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/transport/spdy@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1432,15 +1337,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1449,15 +1356,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/api/rbac/v1@0.24.2 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 + + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1466,15 +1375,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1@0.24.2 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 + + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1483,15 +1394,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/api/core/v1@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1500,15 +1413,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/api/errors@0.24.2 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.42.0 + + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1517,15 +1432,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/api/equality@0.24.2 + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 + + google.golang.org/grpc/health/grpc_health_v1@1.58.3 + + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1534,15 +1453,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/discovery@0.24.2 + google.golang.org/grpc/reflection@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.58.3 - k8s.io/client-go/transport@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.58.3 + + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1551,15 +1474,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/dynamic@0.24.2 + google.golang.org/grpc/health@1.58.3 + + google.golang.org/grpc/health/grpc_health_v1@1.58.3 + + google.golang.org/grpc@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/transport@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1568,15 +1495,21 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/transport/spdy@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 - k8s.io/client-go/rest@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 - k8s.io/client-go/transport@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.58.3 + + google.golang.org/grpc/internal/transport@1.58.3 + + google.golang.org/grpc/internal/pretty@1.58.3 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1585,49 +1518,95 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/pkg/kubeclientmetrics@#36c59d8fafe0 + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 - k8s.io/client-go/rest@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 - k8s.io/client-go/transport@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - golang.org/x/net/http2@#9d032be2e588 - - - -
    • -
    • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/testing@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/transport@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Stack-based Buffer Overflow when processing input that uses pathologically deep nesting.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.32.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
    • Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/kubernetes@0.24.2 - - k8s.io/client-go/rest@0.24.2 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/client-go/transport@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1636,15 +1615,13 @@

      Detailed paths

      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 + github.com/argoproj/pkg/grpc/http@#d56162821bd1 - k8s.io/client-go/transport@0.24.2 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1653,15 +1630,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/gcp@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/transport@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1670,15 +1645,13 @@

      Detailed paths

      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 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - k8s.io/client-go/transport@0.24.2 + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.7.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1687,15 +1660,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - google.golang.org/grpc/reflection@1.45.0 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.45.0 + google.golang.org/grpc@1.58.3 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1704,15 +1677,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - google.golang.org/grpc/health@1.45.0 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - google.golang.org/grpc/health/grpc_health_v1@1.45.0 + google.golang.org/grpc@1.58.3 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1721,17 +1694,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/health@#98ccd3d43fd9 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 - github.com/argoproj/gitops-engine/pkg/utils/kube@#98ccd3d43fd9 + google.golang.org/grpc@1.58.3 - k8s.io/kubectl/pkg/util/openapi@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/discovery@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1740,17 +1711,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/common@#98ccd3d43fd9 - - github.com/argoproj/gitops-engine/pkg/utils/kube@#98ccd3d43fd9 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 - k8s.io/kubectl/pkg/util/openapi@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/discovery@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1759,17 +1728,15 @@

      Detailed paths

      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 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 - k8s.io/client-go/restmapper@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/discovery@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1778,17 +1745,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - sigs.k8s.io/controller-runtime/pkg/envtest@0.11.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane@0.11.0 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/tools/clientcmd@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/client-go/tools/auth@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/client-go/rest@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1797,17 +1762,15 @@

      Detailed paths

      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 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/transport@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1816,17 +1779,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/util/managedfields@0.24.2 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.42.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1835,17 +1796,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/resource@#98ccd3d43fd9 - - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1854,17 +1813,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/common@#98ccd3d43fd9 + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1873,17 +1832,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/hook@#98ccd3d43fd9 + google.golang.org/grpc/reflection@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1892,17 +1851,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/ignore@#98ccd3d43fd9 + google.golang.org/grpc/health@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1911,17 +1870,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/syncwaves@#98ccd3d43fd9 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1930,17 +1889,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/utils/testing@#98ccd3d43fd9 + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1949,17 +1908,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/record@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 - k8s.io/client-go/tools/reference@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1968,17 +1927,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/cache@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 - k8s.io/client-go/tools/pager@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1987,17 +1946,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/pkg/apis/clientauthentication/v1beta1@0.24.2 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 - k8s.io/client-go/pkg/apis/clientauthentication@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2006,17 +1965,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - sigs.k8s.io/controller-runtime@0.11.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - sigs.k8s.io/controller-runtime/pkg/scheme@0.11.0 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2025,17 +1984,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/util/retry@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 - k8s.io/apimachinery/pkg/api/errors@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2044,17 +2003,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/kubectl/pkg/util/resource@0.24.2 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.42.0 - k8s.io/api/core/v1@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2063,17 +2022,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/health@#98ccd3d43fd9 + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 + + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/kubectl/pkg/util/podutils@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2082,17 +2043,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/api/validation@0.24.2 + google.golang.org/grpc/reflection@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1/validation@0.24.2 + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2101,17 +2064,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/portforward@0.24.2 + google.golang.org/grpc/health@1.58.3 + + google.golang.org/grpc/health/grpc_health_v1@1.58.3 - k8s.io/api/core/v1@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/watch@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2120,36 +2085,21 @@

      Detailed paths

      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 + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 - k8s.io/client-go/transport@0.24.2 - - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 - - - -
    • -
    • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 - k8s.io/client-go/kubernetes/fake@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - k8s.io/client-go/testing@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - k8s.io/client-go/rest@0.24.2 + google.golang.org/grpc@1.58.3 - k8s.io/client-go/transport@0.24.2 + google.golang.org/grpc/internal/transport@1.58.3 - k8s.io/apimachinery/pkg/util/net@0.24.2 + google.golang.org/grpc/internal/pretty@1.58.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2158,57 +2108,94 @@

      Detailed paths

      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 + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 - golang.org/x/net/http2@#9d032be2e588 - - - -
    • -
    • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.3.0 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + google.golang.org/grpc@1.58.3 - github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + google.golang.org/grpc/internal/transport@1.58.3 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/pretty@1.58.3 - google.golang.org/grpc/internal/transport@1.45.0 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Authentication Bypass by Capture-replay

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/crypto/ssh +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@0.0.0 and golang.org/x/crypto/ssh@0.16.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
    • 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@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2217,19 +2204,9 @@

      Detailed paths

      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 + golang.org/x/crypto/ssh/knownhosts@0.16.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@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2238,19 +2215,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/cache@#98ccd3d43fd9 - - 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 - - k8s.io/client-go/transport@0.24.2 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2259,19 +2226,11 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync@#98ccd3d43fd9 - - 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 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/transport@0.24.2 + github.com/skeema/knownhosts@1.2.1 - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2280,19 +2239,11 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/utils/kube@#98ccd3d43fd9 - - 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 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/client-go/transport@0.24.2 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2301,19 +2252,13 @@

      Detailed paths

      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 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/watch@0.24.2 + github.com/skeema/knownhosts@1.2.1 - k8s.io/apimachinery/pkg/util/net@0.24.2 + golang.org/x/crypto/ssh/knownhosts@0.16.0 - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2322,19 +2267,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/listers/core/v1@0.24.2 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/client-go/tools/cache@0.24.2 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/tools/pager@0.24.2 + github.com/skeema/knownhosts@1.2.1 - 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@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2343,19 +2282,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/api@#4d8552b0775f - - k8s.io/client-go/tools/cache@0.24.2 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/tools/pager@0.24.2 + github.com/xanzy/ssh-agent@0.3.3 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + golang.org/x/crypto/ssh/agent@0.16.0 - k8s.io/apimachinery/pkg/watch@0.24.2 - - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2364,19 +2297,13 @@

      Detailed paths

      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/tools/cache@0.24.2 - - k8s.io/client-go/tools/pager@0.24.2 + github.com/go-git/go-git/v5@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/apimachinery/pkg/watch@0.24.2 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2385,19 +2312,15 @@

      Detailed paths

      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 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/client-go/tools/pager@0.24.2 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + github.com/skeema/knownhosts@1.2.1 - k8s.io/apimachinery/pkg/watch@0.24.2 + golang.org/x/crypto/ssh/knownhosts@0.16.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2406,19 +2329,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/controller@#4d8552b0775f - - k8s.io/client-go/tools/cache@0.24.2 + github.com/go-git/go-git/v5@5.11.0 - k8s.io/client-go/tools/pager@0.24.2 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/watch@0.24.2 + github.com/skeema/knownhosts@1.2.1 - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2427,19 +2346,15 @@

      Detailed paths

      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 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/client-go/transport/spdy@0.24.2 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/rest@0.24.2 + github.com/xanzy/ssh-agent@0.3.3 - k8s.io/client-go/transport@0.24.2 + golang.org/x/crypto/ssh/agent@0.16.0 - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2448,21 +2363,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/hook@#98ccd3d43fd9 - - github.com/argoproj/gitops-engine/pkg/sync/hook/helm@#98ccd3d43fd9 + github.com/go-git/go-git/v5@5.11.0 - github.com/argoproj/gitops-engine/pkg/sync/common@#98ccd3d43fd9 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - github.com/argoproj/gitops-engine/pkg/utils/kube@#98ccd3d43fd9 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/kubectl/pkg/util/openapi@0.24.2 + github.com/skeema/knownhosts@1.2.1 - k8s.io/client-go/discovery@0.24.2 + golang.org/x/crypto/ssh/knownhosts@0.16.0 - k8s.io/client-go/rest@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2471,286 +2382,232 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/syncwaves@#98ccd3d43fd9 - - github.com/argoproj/gitops-engine/pkg/sync/hook/helm@#98ccd3d43fd9 + github.com/go-git/go-git/v5@5.11.0 - github.com/argoproj/gitops-engine/pkg/sync/common@#98ccd3d43fd9 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - github.com/argoproj/gitops-engine/pkg/utils/kube@#98ccd3d43fd9 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/kubectl/pkg/util/openapi@0.24.2 + github.com/xanzy/ssh-agent@0.3.3 - k8s.io/client-go/discovery@0.24.2 + golang.org/x/crypto/ssh/agent@0.16.0 - k8s.io/client-go/rest@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/crypto/ssh is a SSH client and server

    +

    Affected versions of this package are vulnerable to Authentication Bypass by Capture-replay during the establishment of the secure channel. An attacker can manipulate handshake sequence numbers to delete messages sent immediately after the channel is established.

    +

    Note:

    +
      +
    1. Sequence numbers are only validated once the channel is established and arbitrary messages are allowed during the handshake, allowing them to manipulate the sequence numbers.

      +
    2. +
    3. The potential consequences of the general Terrapin attack are dependent on the messages exchanged after the handshake concludes. If you are using a custom SSH service and do not resort to the authentication protocol, you should check that dropping the first few messages of a connection does not yield security risks.

      +
    4. +
    +

    Impact:

    +

    While cryptographically novel, there is no discernable impact on the integrity of SSH traffic beyond giving the attacker the ability to delete the message that enables some features related to keystroke timing obfuscation. To successfully carry out the exploitation, the connection needs to be protected using either the ChaCha20-Poly1305 or CBC with Encrypt-then-MAC encryption methods. The attacker must also be able to intercept and modify the connection's traffic.

    +

    Workaround

    +

    Temporarily disable the affected chacha20-poly1305@openssh.com encryption and *-etm@openssh.com MAC algorithms in the affected configuration, and use unaffected algorithms like AES-GCM instead.

    +

    Remediation

    +

    Upgrade golang.org/x/crypto/ssh to version 0.17.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + 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 - 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@#9d032be2e588 + github.com/r3labs/diff@1.1.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@#9d032be2e588 - - +
    - -
  • - 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@#9d032be2e588 - - +
  • - -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 - - k8s.io/client-go/kubernetes/scheme@0.24.2 - - 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@#9d032be2e588 - - +
    + +

    MPL-2.0 license

    -
  • -
  • - 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 - - k8s.io/client-go/transport@0.24.2 - - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 - - +
    -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 - - github.com/argoproj/gitops-engine/pkg/sync/ignore@#98ccd3d43fd9 - - github.com/argoproj/gitops-engine/pkg/sync/hook@#98ccd3d43fd9 - - github.com/argoproj/gitops-engine/pkg/sync/hook/helm@#98ccd3d43fd9 - - github.com/argoproj/gitops-engine/pkg/sync/common@#98ccd3d43fd9 - - github.com/argoproj/gitops-engine/pkg/utils/kube@#98ccd3d43fd9 - - 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@#9d032be2e588 - - + -
  • -
  • - 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/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@#9d032be2e588 - - +
  • +
    +

    MPL-2.0 license

    +
    - -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 - - github.com/argoproj/gitops-engine/pkg/diff@#98ccd3d43fd9 - - k8s.io/client-go/kubernetes/scheme@0.24.2 - - 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@#9d032be2e588 - - +
    + medium severity +
    -
  • -
  • - 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@#9d032be2e588 - - +
    -
  • +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + 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 - github.com/argoproj/notifications-engine/pkg/cmd@#4d8552b0775f - - k8s.io/client-go/tools/clientcmd@0.24.2 - - k8s.io/client-go/tools/clientcmd/api/latest@0.24.2 + code.gitea.io/sdk/gitea@0.15.1 - 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@#9d032be2e588 + github.com/hashicorp/go-version@1.2.1
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + 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/argoproj/gitops-engine/pkg/utils/kube/scheme@#98ccd3d43fd9 - - k8s.io/kubernetes/pkg/apis/storage/install@1.24.2 - - k8s.io/kubernetes/pkg/apis/storage/v1beta1@1.24.2 - - k8s.io/kubernetes/pkg/apis/storage@1.24.2 - - k8s.io/kubernetes/pkg/apis/core@1.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@#9d032be2e588 + github.com/hashicorp/go-retryablehttp@0.7.4 @@ -2759,23 +2616,9 @@

      Detailed paths

      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 + github.com/xanzy/go-gitlab@0.86.0 - k8s.io/client-go/transport@0.24.2 - - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + github.com/hashicorp/go-retryablehttp@0.7.4 @@ -2784,23 +2627,11 @@

      Detailed paths

      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 + github.com/argoproj/notifications-engine/pkg/services@#3446d4ae8520 - k8s.io/client-go/rest@0.24.2 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - k8s.io/client-go/transport@0.24.2 - - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + github.com/hashicorp/go-retryablehttp@0.7.4 @@ -2809,25 +2640,13 @@

      Detailed paths

      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 + github.com/argoproj/notifications-engine/pkg/cmd@#3446d4ae8520 - k8s.io/client-go/discovery@0.24.2 + github.com/argoproj/notifications-engine/pkg/services@#3446d4ae8520 - k8s.io/client-go/rest@0.24.2 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - k8s.io/client-go/transport@0.24.2 - - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + github.com/hashicorp/go-retryablehttp@0.7.4 @@ -2836,27 +2655,13 @@

      Detailed paths

      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 + github.com/argoproj/notifications-engine/pkg/subscriptions@#3446d4ae8520 - sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + github.com/argoproj/notifications-engine/pkg/services@#3446d4ae8520 - k8s.io/client-go/restmapper@0.24.2 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - k8s.io/client-go/discovery@0.24.2 - - k8s.io/client-go/rest@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + github.com/hashicorp/go-retryablehttp@0.7.4 @@ -2865,27 +2670,15 @@

      Detailed paths

      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/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 + github.com/argoproj/notifications-engine/pkg/api@#3446d4ae8520 - k8s.io/client-go/restmapper@0.24.2 + github.com/argoproj/notifications-engine/pkg/subscriptions@#3446d4ae8520 - k8s.io/client-go/discovery@0.24.2 + github.com/argoproj/notifications-engine/pkg/services@#3446d4ae8520 - k8s.io/client-go/rest@0.24.2 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - k8s.io/client-go/transport@0.24.2 - - k8s.io/apimachinery/pkg/util/net@0.24.2 - - golang.org/x/net/http2@#9d032be2e588 + github.com/hashicorp/go-retryablehttp@0.7.4 @@ -2894,31 +2687,15 @@

      Detailed paths

      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 + github.com/argoproj/notifications-engine/pkg/controller@#3446d4ae8520 - sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + github.com/argoproj/notifications-engine/pkg/subscriptions@#3446d4ae8520 - sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + github.com/argoproj/notifications-engine/pkg/services@#3446d4ae8520 - k8s.io/client-go/restmapper@0.24.2 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - k8s.io/client-go/discovery@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@#9d032be2e588 + github.com/hashicorp/go-retryablehttp@0.7.4 @@ -2929,40 +2706,17 @@

      Detailed paths


      -

      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) due to improper checks and limitations for the number of entries in the cache, which can allow an attacker to consume unbounded amounts of memory by sending a small number of very large keys.

      -

      Details

      -

      Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

      -

      Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

      -

      One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

      -

      When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

      -

      Two common types of DoS vulnerabilities:

      -
        -
      • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

        -
      • -
      • Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

        -
      • -
      -

      Remediation

      -

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

      -

      References

      - +

      MPL-2.0 license


    -

    Improper Input Validation

    +

    MPL-2.0 license

    @@ -2972,19 +2726,22 @@

    Improper Input Validation


      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • Package Manager: golang
    • - Vulnerable module: + Module: - go.mongodb.org/mongo-driver/bson/bsonrw + github.com/hashicorp/go-cleanhttp
    • Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0, github.com/go-openapi/runtime/middleware@0.19.4 and others + github.com/argoproj/argo-cd/v2@0.0.0, github.com/hashicorp/go-retryablehttp@0.7.4 and others
    @@ -2998,15 +2755,20 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/go-openapi/runtime/middleware@0.19.4 - - github.com/go-openapi/validate@0.19.5 + github.com/hashicorp/go-retryablehttp@0.7.4 - github.com/go-openapi/strfmt@0.19.3 + github.com/hashicorp/go-cleanhttp@0.5.2 + + + + +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 - go.mongodb.org/mongo-driver/bson@1.1.2 + github.com/xanzy/go-gitlab@0.86.0 - go.mongodb.org/mongo-driver/bson/bsonrw@1.1.2 + github.com/hashicorp/go-cleanhttp@0.5.2 @@ -3015,86 +2777,43 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/go-openapi/runtime/middleware@0.19.4 + github.com/xanzy/go-gitlab@0.86.0 + + github.com/hashicorp/go-retryablehttp@0.7.4 - github.com/go-openapi/validate@0.19.5 + github.com/hashicorp/go-cleanhttp@0.5.2 + + + +
  • +
  • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 - github.com/go-openapi/strfmt@0.19.3 + github.com/argoproj/notifications-engine/pkg/services@#3446d4ae8520 - go.mongodb.org/mongo-driver/bson@1.1.2 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - go.mongodb.org/mongo-driver/bson/bsoncodec@1.1.2 + github.com/hashicorp/go-retryablehttp@0.7.4 - go.mongodb.org/mongo-driver/bson/bsonrw@1.1.2 + github.com/hashicorp/go-cleanhttp@0.5.2
  • - - -
    - -
    - -

    Overview

    -

    go.mongodb.org/mongo-driver/bson/bsonrw is a The MongoDB supported driver for Go.

    -

    Affected versions of this package are vulnerable to Improper Input Validation. Specific cstrings input may not be properly validated in the MongoDB Go Driver when marshalling Go objects into BSON. A malicious user could use a Go object with specific string to potentially inject additional fields into marshalled documents.

    -

    Remediation

    -

    Upgrade go.mongodb.org/mongo-driver/bson/bsonrw to version 1.5.1 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Insecure Randomness

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: golang -
    • -
    • - Vulnerable module: - - github.com/Masterminds/goutils -
    • - -
    • Introduced through: - - - github.com/argoproj/argo-cd/v2@0.0.0, github.com/Masterminds/sprig@2.22.0 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
    • Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/Masterminds/sprig@2.22.0 + github.com/argoproj/notifications-engine/pkg/cmd@#3446d4ae8520 + + github.com/argoproj/notifications-engine/pkg/services@#3446d4ae8520 + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-retryablehttp@0.7.4 + + github.com/hashicorp/go-cleanhttp@0.5.2 @@ -3103,13 +2822,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/api@#4d8552b0775f + github.com/argoproj/notifications-engine/pkg/subscriptions@#3446d4ae8520 + + github.com/argoproj/notifications-engine/pkg/services@#3446d4ae8520 - github.com/argoproj/notifications-engine/pkg/templates@#4d8552b0775f + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/sprig@2.22.0 + github.com/hashicorp/go-retryablehttp@0.7.4 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-cleanhttp@0.5.2 @@ -3118,15 +2839,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/cmd@#4d8552b0775f + github.com/argoproj/notifications-engine/pkg/api@#3446d4ae8520 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#3446d4ae8520 - github.com/argoproj/notifications-engine/pkg/api@#4d8552b0775f + github.com/argoproj/notifications-engine/pkg/services@#3446d4ae8520 - github.com/argoproj/notifications-engine/pkg/templates@#4d8552b0775f + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/sprig@2.22.0 + github.com/hashicorp/go-retryablehttp@0.7.4 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-cleanhttp@0.5.2 @@ -3135,15 +2858,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/controller@#4d8552b0775f + github.com/argoproj/notifications-engine/pkg/controller@#3446d4ae8520 - github.com/argoproj/notifications-engine/pkg/api@#4d8552b0775f + github.com/argoproj/notifications-engine/pkg/subscriptions@#3446d4ae8520 - github.com/argoproj/notifications-engine/pkg/templates@#4d8552b0775f + github.com/argoproj/notifications-engine/pkg/services@#3446d4ae8520 - github.com/Masterminds/sprig@2.22.0 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-retryablehttp@0.7.4 + + github.com/hashicorp/go-cleanhttp@0.5.2 @@ -3154,25 +2879,17 @@

      Detailed paths


      -

      Overview

      -

      github.com/masterminds/goutils is a provides users with utility functions to manipulate strings in various ways.

      -

      Affected versions of this package are vulnerable to Insecure Randomness via the RandomAlphaNumeric(int) and CryptoRandomAlphaNumeric(int) functions. Small values of int in the functions above will return a smaller subset of results than they should. For example, RandomAlphaNumeric(1) would always return a digit in the 0-9 range, while RandomAlphaNumeric(4) return around ~7 million of the ~13M possible permutations.

      -

      Remediation

      -

      Upgrade github.com/masterminds/goutils to version 1.1.1 or higher.

      -

      References

      - +

      MPL-2.0 license


    -

    Insecure Randomness

    +

    MPL-2.0 license

    @@ -3182,19 +2899,22 @@

    Insecure Randomness


      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • Package Manager: golang
    • - Vulnerable module: + Module: - github.com/Masterminds/goutils + github.com/gosimple/slug
    • Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 and github.com/gosimple/slug@1.13.1 - github.com/argoproj/argo-cd/v2@0.0.0, github.com/Masterminds/sprig@2.22.0 and others
    @@ -3208,58 +2928,7 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/Masterminds/sprig@2.22.0 - - github.com/Masterminds/goutils@1.1.0 - - - - -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 - - github.com/argoproj/notifications-engine/pkg/api@#4d8552b0775f - - github.com/argoproj/notifications-engine/pkg/templates@#4d8552b0775f - - github.com/Masterminds/sprig@2.22.0 - - github.com/Masterminds/goutils@1.1.0 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 - - github.com/argoproj/notifications-engine/pkg/cmd@#4d8552b0775f - - github.com/argoproj/notifications-engine/pkg/api@#4d8552b0775f - - github.com/argoproj/notifications-engine/pkg/templates@#4d8552b0775f - - github.com/Masterminds/sprig@2.22.0 - - github.com/Masterminds/goutils@1.1.0 - - - -
  • -
  • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 - - github.com/argoproj/notifications-engine/pkg/controller@#4d8552b0775f - - github.com/argoproj/notifications-engine/pkg/api@#4d8552b0775f - - github.com/argoproj/notifications-engine/pkg/templates@#4d8552b0775f - - github.com/Masterminds/sprig@2.22.0 - - github.com/Masterminds/goutils@1.1.0 + github.com/gosimple/slug@1.13.1 @@ -3270,25 +2939,17 @@

    Detailed paths


    -

    Overview

    -

    github.com/masterminds/goutils is a provides users with utility functions to manipulate strings in various ways.

    -

    Affected versions of this package are vulnerable to Insecure Randomness when randomly-generated alphanumeric strings contain significantly less entropy than expected, the RandomAlphaNumeric and CryptoRandomAlphaNumeric functions always return strings containing at least one digit from 0 to 9. This significantly reduces the amount of entropy in short strings generated by these functions.

    -

    Remediation

    -

    Upgrade github.com/masterminds/goutils to version 1.1.1 or higher.

    -

    References

    - +

    MPL-2.0 license


  • -

    Regular Expression Denial of Service (ReDoS)

    +

    Improper Handling of Highly Compressed Data (Data Amplification)

    @@ -3299,18 +2960,21 @@

    Regular Expression Denial of Service (ReDoS)

    • - Package Manager: npm + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + Package Manager: golang
    • Vulnerable module: - cookiejar + github.com/go-jose/go-jose/v3
    • Introduced through: - argo-cd-ui@1.0.0, superagent@7.1.6 and others + github.com/argoproj/argo-cd/v2@0.0.0, github.com/coreos/go-oidc/v3/oidc@3.6.0 and others
    @@ -3322,11 +2986,11 @@

    Detailed paths

    • Introduced through: - argo-cd-ui@1.0.0 + github.com/argoproj/argo-cd/v2@0.0.0 - superagent@7.1.6 + github.com/coreos/go-oidc/v3/oidc@3.6.0 - cookiejar@2.1.3 + github.com/go-jose/go-jose/v3@3.0.0 @@ -3338,91 +3002,20 @@

      Detailed paths


      Overview

      -

      Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) via the Cookie.parse function, which uses an insecure regular expression.

      -

      PoC

      -
      const { CookieJar } = require("cookiejar");
      -        
      -        const jar = new CookieJar();
      -        
      -        const start = performance.now();
      -        const attack = "a" + "t".repeat(50_000);
      -        jar.setCookie(attack);
      -        console.log(`CookieJar.setCookie(): ${performance.now() - start}`);
      -        
      -

      Details

      -

      Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.

      -

      The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.

      -

      Let’s take the following regular expression as an example:

      -
      regex = /A(B|C+)+D/
      -        
      -

      This regular expression accomplishes the following:

      -
        -
      • A The string must start with the letter 'A'
      • -
      • (B|C+)+ The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the + matches one or more times). The + at the end of this section states that we can look for one or more matches of this section.
      • -
      • D Finally, we ensure this section of the string ends with a 'D'
      • -
      -

      The expression would match inputs such as ABBD, ABCCCCD, ABCBCCCD and ACCCCCD

      -

      It most cases, it doesn't take very long for a regex engine to find a match:

      -
      $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
      -        0.04s user 0.01s system 95% cpu 0.052 total
      -        
      -        $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
      -        1.79s user 0.02s system 99% cpu 1.812 total
      -        
      -

      The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.

      -

      Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.

      -

      Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:

      -
        -
      1. CCC
      2. -
      3. CC+C
      4. -
      5. C+CC
      6. -
      7. C+C+C.
      8. -
      -

      The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.

      -

      From there, the number of steps the engine must use to validate a string just continues to grow.

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      StringNumber of C'sNumber of steps
      ACCCX338
      ACCCCX471
      ACCCCCX5136
      ACCCCCCCCCCCCCCX1465,553
      -

      By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.

      +

      Affected versions of this package are vulnerable to Improper Handling of Highly Compressed Data (Data Amplification). An attacker could send a JWE containing compressed data that, when decompressed by Decrypt or DecryptMulti, would use large amounts of memory and CPU.

      Remediation

      -

      Upgrade cookiejar to version 2.1.4 or higher.

      +

      Upgrade github.com/go-jose/go-jose/v3 to version 3.0.3 or higher.

      References


    diff --git a/docs/snyk/v2.8.13/ghcr.io_dexidp_dex_v2.37.0.html b/docs/snyk/v2.8.13/ghcr.io_dexidp_dex_v2.37.0.html new file mode 100644 index 0000000000000..24a737a6ba12f --- /dev/null +++ b/docs/snyk/v2.8.13/ghcr.io_dexidp_dex_v2.37.0.html @@ -0,0 +1,4337 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    March 24th 2024, 12:19:56 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//usr/local/bin/gomplate (gomodules)
    • +
    • ghcr.io/dexidp/dex:v2.37.0/dexidp/dex//usr/local/bin/docker-entrypoint (gomodules)
    • +
    • ghcr.io/dexidp/dex:v2.37.0/dexidp/dex//usr/local/bin/dex (gomodules)
    • +
    +
    + +
    +
    42 known vulnerabilities
    +
    121 vulnerable dependency paths
    +
    786 dependencies
    +
    +
    +
    +
    + +
    +
    +
    +

    Path Traversal

    +
    + +
    + critical severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-git/go-git/v5 +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/go-git/go-git/v5@v5.4.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/go-git/go-git/v5@v5.4.2 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Path Traversal via malicious server replies. An attacker can create and amend files across the filesystem and potentially achieve remote code execution by sending crafted responses to the client.

    +

    Notes:

    +
      +
    1. This is only exploitable if the client is using ChrootOS, which is the default for certain functions such as PlainClone.

      +
    2. +
    3. Applications using BoundOS or in-memory filesystems are not affected by this issue.

      +
    4. +
    5. Users running versions of go-git from v4 and above are recommended to upgrade to v5.11 in order to mitigate this vulnerability.

      +
    6. +
    +

    Workaround

    +

    This vulnerability can be mitigated by limiting the client's use to trustworthy Git servers.

    +

    Remediation

    +

    Upgrade github.com/go-git/go-git/v5 to version 5.11.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    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

    + + +
    + + + +
    +
    +

    CVE-2023-5363

    +
    + +
    + high 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

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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

    + + +
    + + + +
    +
    +

    Heap-based Buffer Overflow

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/mattn/go-sqlite3 +
    • + +
    • Introduced through: + + github.com/dexidp/dex@* and github.com/mattn/go-sqlite3@v1.14.17 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/mattn/go-sqlite3@v1.14.17 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Heap-based Buffer Overflow via the sessionReadRecord function in the ext/session/sqlite3session.c file. An attacker can cause a program crash or execute arbitrary code by manipulating the input to trigger a heap-based buffer overflow.

    +

    Remediation

    +

    Upgrade github.com/mattn/go-sqlite3 to version 1.14.18 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-jose/go-jose/v3 +
    • + +
    • Introduced through: + + github.com/dexidp/dex@* and github.com/go-jose/go-jose/v3@v3.0.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/go-jose/go-jose/v3@v3.0.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) when decrypting JWE inputs. An attacker can cause a denial-of-service by providing a PBES2 encrypted JWE blob with a very large p2c value.

    +

    Details

    +

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

    +

    Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

    +

    One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

    +

    When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

    +

    Two common types of DoS vulnerabilities:

    +
      +
    • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

      +
    • +
    • Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

      +
    • +
    +

    Remediation

    +

    Upgrade github.com/go-jose/go-jose/v3 to version 3.0.1 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. + 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

    + + +
    + + + +
    +
    +

    Improper Check for Unusual or Exceptional Conditions

    +
    + +
    + 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: Generating excessively long X9.42 DH keys or checking + excessively long X9.42 DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_generate_key() to + generate an X9.42 DH key may experience long delays. Likewise, applications + that use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check() + to check an X9.42 DH key or X9.42 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.

    +

    While DH_check() performs all the necessary checks (as of CVE-2023-3817), + DH_check_pub_key() doesn't make any of these checks, and is therefore + vulnerable for excessively large P and Q parameters.

    +

    Likewise, while DH_generate_key() performs a check for an excessively large + P, it doesn't check for an excessively large Q.

    +

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

    +

    DH_generate_key() and DH_check_pub_key() are also 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_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().

    +

    Also vulnerable are the OpenSSL pkey command line application when using the + "-pubcheck" option, as well as the OpenSSL genpkey command line application.

    +

    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.4-r1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + 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: The POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

    +

    Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

    +

    The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

    +

    The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

    +

    The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-0727

    +
    + +
    + 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: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

    +

    Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

    +

    A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

    +

    OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

    +

    We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

    +

    The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/internal/encoding/json +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/protobuf/internal/encoding/json@v1.28.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/protobuf/internal/encoding/json@v1.28.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/protobuf/internal/encoding/json@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/internal/encoding/json to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Stack-based Buffer Overflow

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/protobuf/encoding/protojson@v1.28.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/protobuf/encoding/protojson@v1.28.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Stack-based Buffer Overflow when processing input that uses pathologically deep nesting.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.32.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/protobuf/encoding/protojson@v1.28.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/protobuf/encoding/protojson@v1.28.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Allocation of Resources Without Limits or Throttling

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 Allocation of Resources Without Limits or Throttling when MaxConcurrentStreams handler goroutines running. A a handler is started until one of the existing handlers exits.

    +

    Note:

    +

    This issue is related to CVE-2023-44487

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    Cross-site Scripting (XSS)

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + 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

    + + +
    + + + +
    +
    +

    Authentication Bypass by Capture-replay

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/crypto/ssh +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and golang.org/x/crypto/ssh@v0.0.0-20220525230936-793ad666bf5e + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + golang.org/x/crypto/ssh@v0.0.0-20220525230936-793ad666bf5e + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/crypto/ssh is a SSH client and server

    +

    Affected versions of this package are vulnerable to Authentication Bypass by Capture-replay during the establishment of the secure channel. An attacker can manipulate handshake sequence numbers to delete messages sent immediately after the channel is established.

    +

    Note:

    +
      +
    1. Sequence numbers are only validated once the channel is established and arbitrary messages are allowed during the handshake, allowing them to manipulate the sequence numbers.

      +
    2. +
    3. The potential consequences of the general Terrapin attack are dependent on the messages exchanged after the handshake concludes. If you are using a custom SSH service and do not resort to the authentication protocol, you should check that dropping the first few messages of a connection does not yield security risks.

      +
    4. +
    +

    Impact:

    +

    While cryptographically novel, there is no discernable impact on the integrity of SSH traffic beyond giving the attacker the ability to delete the message that enables some features related to keystroke timing obfuscation. To successfully carry out the exploitation, the connection needs to be protected using either the ChaCha20-Poly1305 or CBC with Encrypt-then-MAC encryption methods. The attacker must also be able to intercept and modify the connection's traffic.

    +

    Workaround

    +

    Temporarily disable the affected chacha20-poly1305@openssh.com encryption and *-etm@openssh.com MAC algorithms in the affected configuration, and use unaffected algorithms like AES-GCM instead.

    +

    Remediation

    +

    Upgrade golang.org/x/crypto/ssh to version 0.17.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + 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

    + +
    + + + +
    +
    +

    Improper Handling of Highly Compressed Data (Data Amplification)

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-jose/go-jose/v3 +
    • + +
    • Introduced through: + + github.com/dexidp/dex@* and github.com/go-jose/go-jose/v3@v3.0.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/go-jose/go-jose/v3@v3.0.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Improper Handling of Highly Compressed Data (Data Amplification). An attacker could send a JWE containing compressed data that, when decompressed by Decrypt or DecryptMulti, would use large amounts of memory and CPU.

    +

    Remediation

    +

    Upgrade github.com/go-jose/go-jose/v3 to version 3.0.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Uncontrolled Resource Consumption ('Resource Exhaustion')

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-git/go-git/v5/plumbing +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/go-git/go-git/v5/plumbing@v5.4.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/go-git/go-git/v5/plumbing@v5.4.2 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    github.com/go-git/go-git/v5/plumbing is a highly extensible git implementation library written in pure Go.

    +

    Affected versions of this package are vulnerable to Uncontrolled Resource Consumption ('Resource Exhaustion') via specially crafted responses from a Git server, which triggers resource exhaustion in clients.

    +

    Note + This is only exploitable if the client is not using the in-memory filesystem supported by the library.

    +

    Workaround

    +

    In cases where a bump to the latest version of go-git is not possible, we recommend limiting its use to only trust-worthy Git servers.

    +

    Details

    +

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

    +

    Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

    +

    One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

    +

    When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

    +

    Two common types of DoS vulnerabilities:

    +
      +
    • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

      +
    • +
    • Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

      +
    • +
    +

    Remediation

    +

    Upgrade github.com/go-git/go-git/v5/plumbing to version 5.11.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-6237

    +
    + +
    + 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

    +

    This vulnerability has not been analyzed by NVD yet.

    +

    Remediation

    +

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

    + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.8.13/haproxy_2.6.14-alpine.html b/docs/snyk/v2.8.13/haproxy_2.6.14-alpine.html new file mode 100644 index 0000000000000..b2b3a76ed356e --- /dev/null +++ b/docs/snyk/v2.8.13/haproxy_2.6.14-alpine.html @@ -0,0 +1,1376 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    March 24th 2024, 12:20:01 am (UTC+00:00)

    +
    +
    + Scanned the following path: +
      +
    • haproxy:2.6.14-alpine (apk)
    • +
    +
    + +
    +
    5 known vulnerabilities
    +
    45 vulnerable dependency paths
    +
    18 dependencies
    +
    +
    +
    +
    +
    + + + + + + + +
    Project docker-image|haproxy
    Path haproxy:2.6.14-alpine
    Package Manager apk
    +
    +
    +
    +
    +

    CVE-2023-5363

    +
    + +
    + high 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

    + + +
    + + + +
    +
    +

    Improper Check for Unusual or Exceptional Conditions

    +
    + +
    + medium 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: Generating excessively long X9.42 DH keys or checking + excessively long X9.42 DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_generate_key() to + generate an X9.42 DH key may experience long delays. Likewise, applications + that use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check() + to check an X9.42 DH key or X9.42 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.

    +

    While DH_check() performs all the necessary checks (as of CVE-2023-3817), + DH_check_pub_key() doesn't make any of these checks, and is therefore + vulnerable for excessively large P and Q parameters.

    +

    Likewise, while DH_generate_key() performs a check for an excessively large + P, it doesn't check for an excessively large Q.

    +

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

    +

    DH_generate_key() and DH_check_pub_key() are also 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_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().

    +

    Also vulnerable are the OpenSSL pkey command line application when using the + "-pubcheck" option, as well as the OpenSSL genpkey command line application.

    +

    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.4-r1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + medium 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: The POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

    +

    Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

    +

    The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

    +

    The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

    +

    The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-0727

    +
    + +
    + medium 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: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

    +

    Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

    +

    A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

    +

    OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

    +

    We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

    +

    The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-6237

    +
    + +
    + 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

    +

    This vulnerability has not been analyzed by NVD yet.

    +

    Remediation

    +

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

    + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.8.13/quay.io_argoproj_argocd_v2.8.13.html b/docs/snyk/v2.8.13/quay.io_argoproj_argocd_v2.8.13.html new file mode 100644 index 0000000000000..01078e7e7a861 --- /dev/null +++ b/docs/snyk/v2.8.13/quay.io_argoproj_argocd_v2.8.13.html @@ -0,0 +1,5054 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    March 24th 2024, 12:20:18 am (UTC+00:00)

    +
    +
    + Scanned the following paths: +
      +
    • quay.io/argoproj/argocd:v2.8.13/argoproj/argocd/Dockerfile (deb)
    • +
    • quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2//usr/local/bin/argocd (gomodules)
    • +
    • quay.io/argoproj/argocd:v2.8.13/kustomize/kustomize/v5//usr/local/bin/kustomize (gomodules)
    • +
    • quay.io/argoproj/argocd:v2.8.13/helm/v3//usr/local/bin/helm (gomodules)
    • +
    • quay.io/argoproj/argocd:v2.8.13/git-lfs/git-lfs//usr/bin/git-lfs (gomodules)
    • +
    +
    + +
    +
    39 known vulnerabilities
    +
    182 vulnerable dependency paths
    +
    2120 dependencies
    +
    +
    +
    +
    + +
    +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/helm/v3 /usr/local/bin/helm +
    • +
    • + 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

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-jose/go-jose/v3 +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and github.com/go-jose/go-jose/v3@v3.0.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + github.com/go-jose/go-jose/v3@v3.0.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) when decrypting JWE inputs. An attacker can cause a denial-of-service by providing a PBES2 encrypted JWE blob with a very large p2c value.

    +

    Details

    +

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

    +

    Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

    +

    One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

    +

    When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

    +

    Two common types of DoS vulnerabilities:

    +
      +
    • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

      +
    • +
    • Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

      +
    • +
    +

    Remediation

    +

    Upgrade github.com/go-jose/go-jose/v3 to version 3.0.1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Directory Traversal

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/helm/v3 /usr/local/bin/helm +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + xz-utils/liblzma5 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and xz-utils/liblzma5@5.2.5-2ubuntu1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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.

    +

    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

    + + +
    + + + +
    +
    +

    CVE-2023-51767

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + openssh/openssh-client +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and openssh/openssh-client@1:8.9p1-3ubuntu0.6 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 openssh.

    +

    References

    + + +
    + + + +
    +
    +

    Information Exposure

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + libgcrypt20 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and libgcrypt20@1.9.4-3ubuntu3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + apt@2.4.11 + + gnupg2/gpgv@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpgsm@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    A timing-based side-channel flaw was found in libgcrypt's RSA implementation. This issue may allow a remote attacker to initiate a Bleichenbacher-style attack, which can lead to the decryption of RSA ciphertexts.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 libgcrypt20.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-26461

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and krb5/libk5crypto3@1.19.2-2ubuntu0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libkrb5support0@1.19.2-2ubuntu0.3 + + + +
    • +
    + +
    + +
    + +

    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.

    +

    Kerberos 5 (aka krb5) 1.21.2 contains a memory leak vulnerability in /krb5/src/lib/gssapi/krb5/k5sealv3.c.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-26462

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and krb5/libk5crypto3@1.19.2-2ubuntu0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libkrb5support0@1.19.2-2ubuntu0.3 + + + +
    • +
    + +
    + +
    + +

    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.

    +

    Kerberos 5 (aka krb5) 1.21.2 contains a memory leak vulnerability in /krb5/src/kdc/ndr.c.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-26458

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and krb5/libk5crypto3@1.19.2-2ubuntu0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libkrb5support0@1.19.2-2ubuntu0.3 + + + +
    • +
    + +
    + +
    + +

    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.

    +

    Kerberos 5 (aka krb5) 1.21.2 contains a memory leak in /krb5/src/lib/rpc/pmap_rmt.c.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    References

    + + +
    + + + +
    +
    +

    LGPL-3.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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

    + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/internal/encoding/json +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/protobuf/internal/encoding/json@v1.31.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + google.golang.org/protobuf/internal/encoding/json@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/internal/encoding/json to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Stack-based Buffer Overflow

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/protobuf/encoding/protojson@v1.31.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Stack-based Buffer Overflow when processing input that uses pathologically deep nesting.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.32.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/protobuf/encoding/protojson@v1.31.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Allocation of Resources Without Limits or Throttling

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/helm/v3 /usr/local/bin/helm +
    • +
    • + 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 Allocation of Resources Without Limits or Throttling when MaxConcurrentStreams handler goroutines running. A a handler is started until one of the existing handlers exits.

    +

    Note:

    +

    This issue is related to CVE-2023-44487

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    Authentication Bypass by Capture-replay

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/crypto/ssh +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and golang.org/x/crypto/ssh@v0.16.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + golang.org/x/crypto/ssh@v0.16.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/crypto/ssh is a SSH client and server

    +

    Affected versions of this package are vulnerable to Authentication Bypass by Capture-replay during the establishment of the secure channel. An attacker can manipulate handshake sequence numbers to delete messages sent immediately after the channel is established.

    +

    Note:

    +
      +
    1. Sequence numbers are only validated once the channel is established and arbitrary messages are allowed during the handshake, allowing them to manipulate the sequence numbers.

      +
    2. +
    3. The potential consequences of the general Terrapin attack are dependent on the messages exchanged after the handshake concludes. If you are using a custom SSH service and do not resort to the authentication protocol, you should check that dropping the first few messages of a connection does not yield security risks.

      +
    4. +
    +

    Impact:

    +

    While cryptographically novel, there is no discernable impact on the integrity of SSH traffic beyond giving the attacker the ability to delete the message that enables some features related to keystroke timing obfuscation. To successfully carry out the exploitation, the connection needs to be protected using either the ChaCha20-Poly1305 or CBC with Encrypt-then-MAC encryption methods. The attacker must also be able to intercept and modify the connection's traffic.

    +

    Workaround

    +

    Temporarily disable the affected chacha20-poly1305@openssh.com encryption and *-etm@openssh.com MAC algorithms in the affected configuration, and use unaffected algorithms like AES-GCM instead.

    +

    Remediation

    +

    Upgrade golang.org/x/crypto/ssh to version 0.17.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Information Exposure

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gnutls28/libgnutls30 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + apt@2.4.11 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + openldap/libldap-2.5-0@2.5.17+dfsg-0ubuntu0.22.04.1 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + rtmpdump/librtmp1@2.4+20151223.gitfa8646d.1-2build4 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    A flaw was found in GnuTLS. The Minerva attack is a cryptographic vulnerability that exploits deterministic behavior in systems like GnuTLS, leading to side-channel leaks. In specific scenarios, such as when using the GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE flag, it can result in a noticeable step in nonce size from 513 to 512 bits, exposing a potential timing side-channel.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 gnutls28.

    +

    References

    + + +
    + + + +
    +
    +

    Uncaught Exception

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gnutls28/libgnutls30 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + apt@2.4.11 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + openldap/libldap-2.5-0@2.5.17+dfsg-0ubuntu0.22.04.1 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + rtmpdump/librtmp1@2.4+20151223.gitfa8646d.1-2build4 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    A flaw has been discovered in GnuTLS where an application crash can be induced when attempting to verify a specially crafted .pem bundle using the "certtool --verify-chain" command.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 gnutls28.

    +

    References

    + + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/helm/v3 /usr/local/bin/helm +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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

    + +
    + + + +
    +
    +

    Improper Handling of Highly Compressed Data (Data Amplification)

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-jose/go-jose/v3 +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and github.com/go-jose/go-jose/v3@v3.0.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + github.com/go-jose/go-jose/v3@v3.0.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Improper Handling of Highly Compressed Data (Data Amplification). An attacker could send a JWE containing compressed data that, when decompressed by Decrypt or DecryptMulti, would use large amounts of memory and CPU.

    +

    Remediation

    +

    Upgrade github.com/go-jose/go-jose/v3 to version 3.0.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + bash +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and bash@5.1-6ubuntu1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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. + 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

    +

    Upgrade Ubuntu:22.04 bash to version 5.1-6ubuntu1.1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-7008

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + systemd/libsystemd0 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and systemd/libsystemd0@249.11-0ubuntu3.12 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + apt@2.4.11 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + procps/libprocps8@2:3.3.17-6ubuntu2.1 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + util-linux@2.37.2-4ubuntu3 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + util-linux/bsdutils@1:2.37.2-4ubuntu3 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + systemd/libudev1@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + libfido2/libfido2-1@1.10.0-1 + + systemd/libudev1@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + util-linux@2.37.2-4ubuntu3 + + systemd/libudev1@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + systemd/libudev1@249.11-0ubuntu3.12 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    A vulnerability was found in systemd-resolved. This issue may allow systemd-resolved to accept records of DNSSEC-signed domains even when they have no signature, allowing man-in-the-middles (or the upstream DNS resolver) to manipulate records.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 systemd.

    +

    References

    + + +
    + + + +
    +
    +

    Arbitrary Code Injection

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + shadow/passwd +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and shadow/passwd@1:4.8.1-2ubuntu2.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + shadow/login@1:4.8.1-2ubuntu2.2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream shadow package and not the shadow package as distributed by Ubuntu. + 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

    + + +
    + + + +
    +
    +

    Uncontrolled Recursion

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + pcre3/libpcre3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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. + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + patch +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and patch@2.7.6-7build2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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. + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + patch +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and patch@2.7.6-7build2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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. + 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-50495

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + ncurses/libtinfo6 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and ncurses/libtinfo6@6.3-2ubuntu0.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + bash@5.1-6ubuntu1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + less@590-1ubuntu0.22.04.2 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + libedit/libedit2@3.1-20210910-1build1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/ncurses-bin@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + util-linux@2.37.2-4ubuntu3 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + readline/libreadline8@8.1.2-1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + pinentry/pinentry-curses@1.1.1-1build2 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + pinentry/pinentry-curses@1.1.1-1build2 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/ncurses-base@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/ncurses-bin@6.3-2ubuntu0.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    NCurse v6.4-20230418 was discovered to contain a segmentation fault via the component _nc_wrap_entry().

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 ncurses.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-45918

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + ncurses/libtinfo6 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and ncurses/libtinfo6@6.3-2ubuntu0.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + bash@5.1-6ubuntu1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + less@590-1ubuntu0.22.04.2 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + libedit/libedit2@3.1-20210910-1build1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/ncurses-bin@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + util-linux@2.37.2-4ubuntu3 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + readline/libreadline8@8.1.2-1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + pinentry/pinentry-curses@1.1.1-1build2 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + pinentry/pinentry-curses@1.1.1-1build2 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/ncurses-base@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + ncurses/ncurses-bin@6.3-2ubuntu0.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    ncurses 6.4-20230610 has a NULL pointer dereference in tgetstr in tinfo/lib_termcap.c.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 ncurses.

    +

    References

    + + +
    + + + +
    +
    +

    Resource Exhaustion

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + libzstd/libzstd1 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and libzstd/libzstd1@1.4.8+dfsg-3build1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and krb5/libk5crypto3@1.19.2-2ubuntu0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + krb5/libkrb5support0@1.19.2-2ubuntu0.3 + + + +
    • +
    + +
    + +
    + +

    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.

    +

    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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gnupg2/gpgv +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and gnupg2/gpgv@2.2.27-3ubuntu2.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gpgv@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + apt@2.4.11 + + gnupg2/gpgv@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpgv@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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.8.13 + + 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.8.13 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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.8.13 + + gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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.8.13 + + 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.8.13 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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.8.13 + + 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.8.13 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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.8.13 + + gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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.8.13 + + gnupg2/gpgsm@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpgsm@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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. + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + glibc/libc-bin +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and glibc/libc-bin@2.35-0ubuntu3.6 + +
    • +
    + +
    + + +

    Detailed paths

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

    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.

    +

    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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + git/git-man +
    • + +
    • Introduced through: + + + docker-image|quay.io/argoproj/argocd@v2.8.13, git@1:2.34.1-1ubuntu1.10 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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.8.13 + + git@1:2.34.1-1ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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. + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gcc-12/libstdc++6 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + apt@2.4.11 + + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + gcc-12/gcc-12-base@12.3.0-1ubuntu1~22.04 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + 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. + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.8.13/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + coreutils +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.13 and coreutils@8.32-4.1ubuntu1.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.13 + + coreutils@8.32-4.1ubuntu1.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream coreutils package and not the coreutils package as distributed by Ubuntu. + 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

    + + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.8.13/redis_7.0.11-alpine.html b/docs/snyk/v2.8.13/redis_7.0.11-alpine.html new file mode 100644 index 0000000000000..9df9ec7f93123 --- /dev/null +++ b/docs/snyk/v2.8.13/redis_7.0.11-alpine.html @@ -0,0 +1,2032 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    March 24th 2024, 12:20:22 am (UTC+00:00)

    +
    +
    + Scanned the following path: +
      +
    • redis:7.0.11-alpine (apk)
    • +
    +
    + +
    +
    9 known vulnerabilities
    +
    77 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

    + + +
    + + + +
    +
    +

    CVE-2023-5363

    +
    + +
    + high 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

    + + +
    + + + +
    +
    +

    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. + 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

    + + +
    + + + +
    +
    +

    Improper Check for Unusual or Exceptional Conditions

    +
    + +
    + 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: Generating excessively long X9.42 DH keys or checking + excessively long X9.42 DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_generate_key() to + generate an X9.42 DH key may experience long delays. Likewise, applications + that use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check() + to check an X9.42 DH key or X9.42 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.

    +

    While DH_check() performs all the necessary checks (as of CVE-2023-3817), + DH_check_pub_key() doesn't make any of these checks, and is therefore + vulnerable for excessively large P and Q parameters.

    +

    Likewise, while DH_generate_key() performs a check for an excessively large + P, it doesn't check for an excessively large Q.

    +

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

    +

    DH_generate_key() and DH_check_pub_key() are also 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_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().

    +

    Also vulnerable are the OpenSSL pkey command line application when using the + "-pubcheck" option, as well as the OpenSSL genpkey command line application.

    +

    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.4-r1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + 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: The POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

    +

    Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

    +

    The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

    +

    The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

    +

    The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-0727

    +
    + +
    + 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: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

    +

    Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

    +

    A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

    +

    OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

    +

    We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

    +

    The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-6237

    +
    + +
    + 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

    +

    This vulnerability has not been analyzed by NVD yet.

    +

    Remediation

    +

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

    + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.6.0-rc4/argocd-iac-install.html b/docs/snyk/v2.9.9/argocd-iac-install.html similarity index 73% rename from docs/snyk/v2.6.0-rc4/argocd-iac-install.html rename to docs/snyk/v2.9.9/argocd-iac-install.html index c40c5f73ed37f..e25fc886459cb 100644 --- a/docs/snyk/v2.6.0-rc4/argocd-iac-install.html +++ b/docs/snyk/v2.9.9/argocd-iac-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    January 22nd 2023, 12:19:28 am

    +

    March 24th 2024, 12:19:27 am (UTC+00:00)

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

    Snyk test report

    -
    32 total issues
    +
    38 total issues
    @@ -483,7 +483,7 @@

    Snyk test report

    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -494,7 +494,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -507,29 +507,29 @@

      Role with dangerous permissions

    • - Line number: 15177 + Line number: 20316

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -540,7 +540,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -553,29 +553,29 @@

      Role with dangerous permissions

    • - Line number: 15254 + Line number: 20401

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -586,7 +586,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -599,29 +599,29 @@

      Role with dangerous permissions

    • - Line number: 15282 + Line number: 20429

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -632,42 +632,42 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: [DocId: 13] - rules[3] + rules[1] resources
    • - Line number: 15326 + Line number: 20459

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -678,42 +678,42 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: [DocId: 13] - rules[1] + rules[3] resources
    • - Line number: 15308 + Line number: 20477

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -724,7 +724,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -737,24 +737,24 @@

      Role with dangerous permissions

    • - Line number: 15342 + Line number: 20493

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    @@ -770,11 +770,11 @@

    Container could be running with outdated image

    • - Public ID: SNYK-CC-K8S-42 + Public ID: SNYK-CC-K8S-42
    • Introduced through: - [DocId: 46] + [DocId: 45] spec @@ -789,7 +789,7 @@

      Container could be running with outdated image

    • - Line number: 16346 + Line number: 21633
    @@ -806,7 +806,7 @@

    Remediation

    @@ -822,11 +822,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 42] + [DocId: 41] input @@ -847,7 +847,7 @@

      Container has no CPU limit

    • - Line number: 15809 + Line number: 20978
    @@ -864,7 +864,7 @@

    Remediation

    @@ -880,11 +880,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 43] + [DocId: 42] input @@ -905,7 +905,7 @@

      Container has no CPU limit

    • - Line number: 15982 + Line number: 21223
    @@ -922,7 +922,7 @@

    Remediation

    @@ -938,11 +938,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 43] + [DocId: 42] input @@ -963,7 +963,7 @@

      Container has no CPU limit

    • - Line number: 15948 + Line number: 21189
    @@ -980,7 +980,7 @@

    Remediation

    @@ -996,11 +996,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 44] + [DocId: 43] input @@ -1021,7 +1021,7 @@

      Container has no CPU limit

    • - Line number: 16038 + Line number: 21283
    @@ -1038,7 +1038,7 @@

    Remediation

    @@ -1054,11 +1054,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 45] + [DocId: 44] input @@ -1079,7 +1079,7 @@

      Container has no CPU limit

    • - Line number: 16112 + Line number: 21376
    @@ -1096,7 +1096,7 @@

    Remediation

    @@ -1112,11 +1112,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 46] + [DocId: 45] input @@ -1137,7 +1137,7 @@

      Container has no CPU limit

    • - Line number: 16346 + Line number: 21633
    @@ -1154,7 +1154,7 @@

    Remediation

    @@ -1170,11 +1170,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 46] + [DocId: 45] input @@ -1195,7 +1195,7 @@

      Container has no CPU limit

    • - Line number: 16168 + Line number: 21433
    @@ -1212,7 +1212,7 @@

    Remediation

    @@ -1228,11 +1228,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 47] + [DocId: 46] input @@ -1253,7 +1253,7 @@

      Container has no CPU limit

    • - Line number: 16431 + Line number: 21718
    @@ -1270,7 +1270,7 @@

    Remediation

    @@ -1286,11 +1286,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 48] + [DocId: 47] input @@ -1311,7 +1311,7 @@

      Container has no CPU limit

    • - Line number: 16735 + Line number: 22040
    @@ -1328,7 +1328,7 @@

    Remediation

    @@ -1344,11 +1344,11 @@

    Container is running with multiple open ports

    • - Public ID: SNYK-CC-K8S-36 + Public ID: SNYK-CC-K8S-36
    • Introduced through: - [DocId: 43] + [DocId: 42] spec @@ -1363,7 +1363,7 @@

      Container is running with multiple open ports

    • - Line number: 15962 + Line number: 21203
    @@ -1380,12 +1380,12 @@

    Remediation

    -

    Container is running with writable root filesystem

    +

    Container is running without liveness probe

    @@ -1396,13 +1396,11 @@

    Container is running with writable root filesystem

    • - Public ID: SNYK-CC-K8S-8 + Public ID: SNYK-CC-K8S-41
    • Introduced through: - [DocId: 45] - - input + [DocId: 41] spec @@ -1410,33 +1408,31 @@

      Container is running with writable root filesystem

      spec - containers[redis] - - securityContext + containers[argocd-applicationset-controller] - readOnlyRootFilesystem + livenessProbe
    • - Line number: 16122 + Line number: 20978

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    +

    Add `livenessProbe` attribute


    @@ -1452,7 +1448,7 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: @@ -1464,14 +1460,14 @@

      Container is running without liveness probe

      spec - containers[argocd-applicationset-controller] + containers[dex] livenessProbe
    • - Line number: 15809 + Line number: 21189
    @@ -1488,7 +1484,7 @@

    Remediation

    @@ -1504,11 +1500,11 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: - [DocId: 43] + [DocId: 44] spec @@ -1516,14 +1512,14 @@

      Container is running without liveness probe

      spec - containers[dex] + containers[redis] livenessProbe
    • - Line number: 15948 + Line number: 21376
    @@ -1540,12 +1536,12 @@

    Remediation

    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1556,11 +1552,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 43] + [DocId: 41] + + input spec @@ -1568,36 +1566,40 @@

      Container is running without liveness probe

      spec - initContainers[copyutil] + containers[argocd-applicationset-controller] - livenessProbe + resources + + limits + + memory
    • - Line number: 15982 + Line number: 20978

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1608,11 +1610,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 45] + [DocId: 42] + + input spec @@ -1620,36 +1624,40 @@

      Container is running without liveness probe

      spec - containers[redis] + containers[dex] - livenessProbe + resources + + limits + + memory
    • - Line number: 16112 + Line number: 21189

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1660,11 +1668,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 46] + [DocId: 42] + + input spec @@ -1674,29 +1684,33 @@

      Container is running without liveness probe

      initContainers[copyutil] - livenessProbe + resources + + limits + + memory
    • - Line number: 16346 + Line number: 21223

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    @@ -1712,11 +1726,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 42] + [DocId: 43] input @@ -1726,7 +1740,7 @@

      Container is running without memory limit

      spec - containers[argocd-applicationset-controller] + containers[argocd-notifications-controller] resources @@ -1737,7 +1751,7 @@

      Container is running without memory limit

    • - Line number: 15809 + Line number: 21283
    @@ -1754,7 +1768,7 @@

    Remediation

    @@ -1770,11 +1784,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 43] + [DocId: 44] input @@ -1784,7 +1798,7 @@

      Container is running without memory limit

      spec - containers[dex] + containers[redis] resources @@ -1795,7 +1809,7 @@

      Container is running without memory limit

    • - Line number: 15948 + Line number: 21376
    @@ -1812,7 +1826,7 @@

    Remediation

    @@ -1828,11 +1842,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 43] + [DocId: 45] input @@ -1853,7 +1867,7 @@

      Container is running without memory limit

    • - Line number: 15982 + Line number: 21633
    @@ -1870,7 +1884,7 @@

    Remediation

    @@ -1886,11 +1900,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 44] + [DocId: 45] input @@ -1900,7 +1914,7 @@

      Container is running without memory limit

      spec - containers[argocd-notifications-controller] + containers[argocd-repo-server] resources @@ -1911,7 +1925,7 @@

      Container is running without memory limit

    • - Line number: 16038 + Line number: 21433
    @@ -1928,7 +1942,7 @@

    Remediation

    @@ -1944,11 +1958,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 45] + [DocId: 46] input @@ -1958,7 +1972,7 @@

      Container is running without memory limit

      spec - containers[redis] + containers[argocd-server] resources @@ -1969,7 +1983,7 @@

      Container is running without memory limit

    • - Line number: 16112 + Line number: 21718
    @@ -1986,7 +2000,7 @@

    Remediation

    @@ -2002,11 +2016,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 46] + [DocId: 47] input @@ -2016,7 +2030,7 @@

      Container is running without memory limit

      spec - initContainers[copyutil] + containers[argocd-application-controller] resources @@ -2027,7 +2041,7 @@

      Container is running without memory limit

    • - Line number: 16346 + Line number: 22040
    @@ -2044,12 +2058,12 @@

    Remediation

    -

    Container is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2060,11 +2074,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: - [DocId: 46] + [DocId: 41] input @@ -2074,40 +2088,94 @@

      Container is running without memory limit

      spec - containers[argocd-repo-server] + containers[argocd-applicationset-controller] - resources + securityContext - limits + runAsUser + +
    • + +
    • + Line number: 21113 +
    • +
    + +
    + +

    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] - memory + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser
    • - Line number: 16168 + Line number: 21231

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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 is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2118,11 +2186,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: - [DocId: 47] + [DocId: 42] input @@ -2132,40 +2200,94 @@

      Container is running without memory limit

      spec - containers[argocd-server] + containers[dex] - resources + securityContext - limits + runAsUser + +
    • + +
    • + Line number: 21206 +
    • +
    + +
    + +

    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] - memory + input + + spec + + template + + spec + + containers[argocd-notifications-controller] + + securityContext + + runAsUser
    • - Line number: 16431 + Line number: 21310

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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 is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2176,11 +2298,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: - [DocId: 48] + [DocId: 44] input @@ -2190,35 +2312,257 @@

      Container is running without memory limit

      spec - containers[argocd-application-controller] + containers[redis] - resources + securityContext - limits + runAsUser + +
    • + +
    • + Line number: 21386 +
    • +
    + +
    + +

    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] - memory + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser
    • - Line number: 16735 + Line number: 21640

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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: 21606 +
    • +
    + +
    + +

    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: 21950 +
    • +
    + +
    + +

    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: 22188 +
    • +
    + +
    + +

    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.4.19/argocd-iac-namespace-install.html b/docs/snyk/v2.9.9/argocd-iac-namespace-install.html similarity index 73% rename from docs/snyk/v2.4.19/argocd-iac-namespace-install.html rename to docs/snyk/v2.9.9/argocd-iac-namespace-install.html index 389075c733ec2..5fd494538c87c 100644 --- a/docs/snyk/v2.4.19/argocd-iac-namespace-install.html +++ b/docs/snyk/v2.9.9/argocd-iac-namespace-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    January 22nd 2023, 12:23:01 am

    +

    March 24th 2024, 12:19:35 am (UTC+00:00)

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

    Snyk test report

    -
    32 total issues
    +
    38 total issues
    @@ -483,7 +483,7 @@

    Snyk test report

    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -494,7 +494,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -507,29 +507,29 @@

      Role with dangerous permissions

    • - Line number: 73 + Line number: 77

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -540,7 +540,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -553,29 +553,29 @@

      Role with dangerous permissions

    • - Line number: 150 + Line number: 162

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -586,7 +586,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -599,29 +599,29 @@

      Role with dangerous permissions

    • - Line number: 178 + Line number: 190

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -632,42 +632,42 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: [DocId: 10] - rules[3] + rules[1] resources
    • - Line number: 222 + Line number: 220

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -678,42 +678,42 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: [DocId: 10] - rules[1] + rules[3] resources
    • - Line number: 204 + Line number: 238

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    -

    Role with dangerous permissions

    +

    Role or ClusterRole with dangerous permissions

    @@ -724,7 +724,7 @@

    Role with dangerous permissions

    • - Public ID: SNYK-CC-K8S-47 + Public ID: SNYK-CC-K8S-47
    • Introduced through: @@ -737,24 +737,24 @@

      Role with dangerous permissions

    • - Line number: 238 + Line number: 254

    Impact

    -

    Using this role grants dangerous permissions

    +

    Using this role grants dangerous permissions. For a ClusterRole this would be considered high severity.

    Remediation

    -

    Consider removing this permissions

    +

    Consider removing these permissions


    @@ -770,11 +770,11 @@

    Container could be running with outdated image

    • - Public ID: SNYK-CC-K8S-42 + Public ID: SNYK-CC-K8S-42
    • Introduced through: - [DocId: 39] + [DocId: 38] spec @@ -789,7 +789,7 @@

      Container could be running with outdated image

    • - Line number: 1025 + Line number: 1288
    @@ -806,7 +806,7 @@

    Remediation

    @@ -822,11 +822,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 35] + [DocId: 34] input @@ -847,7 +847,7 @@

      Container has no CPU limit

    • - Line number: 611 + Line number: 633
    @@ -864,7 +864,7 @@

    Remediation

    @@ -880,11 +880,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 36] + [DocId: 35] input @@ -905,7 +905,7 @@

      Container has no CPU limit

    • - Line number: 711 + Line number: 878
    @@ -922,7 +922,7 @@

    Remediation

    @@ -938,11 +938,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 36] + [DocId: 35] input @@ -963,7 +963,7 @@

      Container has no CPU limit

    • - Line number: 688 + Line number: 844
    @@ -980,7 +980,7 @@

    Remediation

    @@ -996,11 +996,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 37] + [DocId: 36] input @@ -1021,7 +1021,7 @@

      Container has no CPU limit

    • - Line number: 754 + Line number: 938
    @@ -1038,7 +1038,7 @@

    Remediation

    @@ -1054,11 +1054,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 38] + [DocId: 37] input @@ -1079,7 +1079,7 @@

      Container has no CPU limit

    • - Line number: 826 + Line number: 1031
    @@ -1096,7 +1096,7 @@

    Remediation

    @@ -1112,11 +1112,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 39] + [DocId: 38] input @@ -1137,7 +1137,7 @@

      Container has no CPU limit

    • - Line number: 1025 + Line number: 1288
    @@ -1154,7 +1154,7 @@

    Remediation

    @@ -1170,11 +1170,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 39] + [DocId: 38] input @@ -1195,7 +1195,7 @@

      Container has no CPU limit

    • - Line number: 880 + Line number: 1088
    @@ -1212,7 +1212,7 @@

    Remediation

    @@ -1228,11 +1228,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 40] + [DocId: 39] input @@ -1253,7 +1253,7 @@

      Container has no CPU limit

    • - Line number: 1108 + Line number: 1373
    @@ -1270,7 +1270,7 @@

    Remediation

    @@ -1286,11 +1286,11 @@

    Container has no CPU limit

    • - Public ID: SNYK-CC-K8S-5 + Public ID: SNYK-CC-K8S-5
    • Introduced through: - [DocId: 41] + [DocId: 40] input @@ -1311,7 +1311,7 @@

      Container has no CPU limit

    • - Line number: 1368 + Line number: 1695
    @@ -1328,7 +1328,7 @@

    Remediation

    @@ -1344,11 +1344,11 @@

    Container is running with multiple open ports

    • - Public ID: SNYK-CC-K8S-36 + Public ID: SNYK-CC-K8S-36
    • Introduced through: - [DocId: 36] + [DocId: 35] spec @@ -1363,7 +1363,7 @@

      Container is running with multiple open ports

    • - Line number: 695 + Line number: 858
    @@ -1380,12 +1380,12 @@

    Remediation

    -

    Container is running with writable root filesystem

    +

    Container is running without liveness probe

    @@ -1396,13 +1396,11 @@

    Container is running with writable root filesystem

    • - Public ID: SNYK-CC-K8S-8 + Public ID: SNYK-CC-K8S-41
    • Introduced through: - [DocId: 38] - - input + [DocId: 34] spec @@ -1410,33 +1408,31 @@

      Container is running with writable root filesystem

      spec - containers[redis] - - securityContext + containers[argocd-applicationset-controller] - readOnlyRootFilesystem + livenessProbe
    • - Line number: 836 + Line number: 633

    Impact

    -

    Compromised process could abuse writable root filesystem to elevate privileges

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    Remediation

    -

    Set `securityContext.readOnlyRootFilesystem` to `true`

    +

    Add `livenessProbe` attribute


    @@ -1452,7 +1448,7 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: @@ -1464,14 +1460,14 @@

      Container is running without liveness probe

      spec - containers[argocd-applicationset-controller] + containers[dex] livenessProbe
    • - Line number: 611 + Line number: 844
    @@ -1488,7 +1484,7 @@

    Remediation

    @@ -1504,11 +1500,11 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-41
    • Introduced through: - [DocId: 36] + [DocId: 37] spec @@ -1516,14 +1512,14 @@

      Container is running without liveness probe

      spec - containers[dex] + containers[redis] livenessProbe
    • - Line number: 688 + Line number: 1031
    @@ -1540,12 +1536,12 @@

    Remediation

    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1556,11 +1552,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 36] + [DocId: 34] + + input spec @@ -1568,36 +1566,40 @@

      Container is running without liveness probe

      spec - initContainers[copyutil] + containers[argocd-applicationset-controller] - livenessProbe + resources + + limits + + memory
    • - Line number: 711 + Line number: 633

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1608,11 +1610,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 38] + [DocId: 35] + + input spec @@ -1620,36 +1624,40 @@

      Container is running without liveness probe

      spec - containers[redis] + containers[dex] - livenessProbe + resources + + limits + + memory
    • - Line number: 826 + Line number: 844

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    -

    Container is running without liveness probe

    +

    Container is running without memory limit

    @@ -1660,11 +1668,13 @@

    Container is running without liveness probe

    • - Public ID: SNYK-CC-K8S-41 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 39] + [DocId: 35] + + input spec @@ -1674,29 +1684,33 @@

      Container is running without liveness probe

      initContainers[copyutil] - livenessProbe + resources + + limits + + memory
    • - Line number: 1025 + Line number: 878

    Impact

    -

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    Remediation

    -

    Add `livenessProbe` attribute

    +

    Set `resources.limits.memory` value


    @@ -1712,11 +1726,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 35] + [DocId: 36] input @@ -1726,7 +1740,7 @@

      Container is running without memory limit

      spec - containers[argocd-applicationset-controller] + containers[argocd-notifications-controller] resources @@ -1737,7 +1751,7 @@

      Container is running without memory limit

    • - Line number: 611 + Line number: 938
    @@ -1754,7 +1768,7 @@

    Remediation

    @@ -1770,11 +1784,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 36] + [DocId: 37] input @@ -1784,7 +1798,7 @@

      Container is running without memory limit

      spec - containers[dex] + containers[redis] resources @@ -1795,7 +1809,7 @@

      Container is running without memory limit

    • - Line number: 688 + Line number: 1031
    @@ -1812,7 +1826,7 @@

    Remediation

    @@ -1828,11 +1842,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 36] + [DocId: 38] input @@ -1853,7 +1867,7 @@

      Container is running without memory limit

    • - Line number: 711 + Line number: 1288
    @@ -1870,7 +1884,7 @@

    Remediation

    @@ -1886,11 +1900,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 37] + [DocId: 38] input @@ -1900,7 +1914,7 @@

      Container is running without memory limit

      spec - containers[argocd-notifications-controller] + containers[argocd-repo-server] resources @@ -1911,7 +1925,7 @@

      Container is running without memory limit

    • - Line number: 754 + Line number: 1088
    @@ -1928,7 +1942,7 @@

    Remediation

    @@ -1944,11 +1958,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 38] + [DocId: 39] input @@ -1958,7 +1972,7 @@

      Container is running without memory limit

      spec - containers[redis] + containers[argocd-server] resources @@ -1969,7 +1983,7 @@

      Container is running without memory limit

    • - Line number: 826 + Line number: 1373
    @@ -1986,7 +2000,7 @@

    Remediation

    @@ -2002,11 +2016,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-4
    • Introduced through: - [DocId: 39] + [DocId: 40] input @@ -2016,7 +2030,7 @@

      Container is running without memory limit

      spec - initContainers[copyutil] + containers[argocd-application-controller] resources @@ -2027,7 +2041,7 @@

      Container is running without memory limit

    • - Line number: 1025 + Line number: 1695
    @@ -2044,12 +2058,12 @@

    Remediation

    -

    Container is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2060,11 +2074,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: - [DocId: 39] + [DocId: 34] input @@ -2074,40 +2088,94 @@

      Container is running without memory limit

      spec - containers[argocd-repo-server] + containers[argocd-applicationset-controller] - resources + securityContext - limits + runAsUser + +
    • + +
    • + Line number: 768 +
    • +
    + +
    + +

    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] - memory + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser
    • - Line number: 880 + Line number: 886

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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 is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2118,11 +2186,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: - [DocId: 40] + [DocId: 35] input @@ -2132,40 +2200,94 @@

      Container is running without memory limit

      spec - containers[argocd-server] + containers[dex] - resources + securityContext - limits + runAsUser + +
    • + +
    • + Line number: 861 +
    • +
    + +
    + +

    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] - memory + input + + spec + + template + + spec + + containers[argocd-notifications-controller] + + securityContext + + runAsUser
    • - Line number: 1108 + Line number: 965

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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 is running without memory limit

    +

    Container's or Pod's UID could clash with host's UID

    @@ -2176,11 +2298,11 @@

    Container is running without memory limit

    • - Public ID: SNYK-CC-K8S-4 + Public ID: SNYK-CC-K8S-11
    • Introduced through: - [DocId: 41] + [DocId: 37] input @@ -2190,35 +2312,257 @@

      Container is running without memory limit

      spec - containers[argocd-application-controller] + containers[redis] - resources + securityContext - limits + runAsUser + +
    • + +
    • + Line number: 1041 +
    • +
    + +
    + +

    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] - memory + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser
    • - Line number: 1368 + Line number: 1295

    Impact

    -

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    Remediation

    -

    Set `resources.limits.memory` value

    +

    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: 1261 +
    • +
    + +
    + +

    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: 1605 +
    • +
    + +
    + +

    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: 1843 +
    • +
    + +
    + +

    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.4.19/argocd-test.html b/docs/snyk/v2.9.9/argocd-test.html similarity index 61% rename from docs/snyk/v2.4.19/argocd-test.html rename to docs/snyk/v2.9.9/argocd-test.html index 4a113207d1bf2..c4894f56b168a 100644 --- a/docs/snyk/v2.4.19/argocd-test.html +++ b/docs/snyk/v2.9.9/argocd-test.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,19 +456,20 @@

    Snyk test report

    -

    January 22nd 2023, 12:21:39 am

    +

    March 24th 2024, 12:17:43 am (UTC+00:00)

    Scanned the following paths:
      -
    • /argo-cd/argoproj/argo-cd/v2 (gomodules)
    • /argo-cd (yarn)
    • +
    • /argo-cd/argoproj/argo-cd/v2/go.mod (gomodules)
    • +
    • /argo-cd/ui/yarn.lock (yarn)
    -
    8 known vulnerabilities
    -
    128 vulnerable dependency paths
    -
    1656 dependencies
    +
    12 known vulnerabilities
    +
    133 vulnerable dependency paths
    +
    1917 dependencies
    @@ -476,206 +477,33 @@

    Snyk test report

    -
    -

    Server-side Request Forgery (SSRF)

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: npm -
    • -
    • - Vulnerable module: - - parse-url -
    • - -
    • Introduced through: - - - argo-cd-ui@1.0.0, git-url-parse@11.6.0 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - argo-cd-ui@1.0.0 - - git-url-parse@11.6.0 - - git-up@4.0.5 - - parse-url@6.0.5 - - - -
    • -
    - -
    - -
    - -

    Overview

    -

    parse-url is an An advanced url parser supporting git urls too.

    -

    Affected versions of this package are vulnerable to Server-side Request Forgery (SSRF) due to improper detection of protocol, resource, and pathname fields. Exploiting this vulnerability results in bypassing protocol verification.

    -

    PoC:

    -
    import parseUrl from "parse-url";
    -        import fetch from 'node-fetch';
    -        var parsed=parseUrl("http://nnnn@localhost:808:/?id=xss")
    -        if(parsed.resource=="localhost"){
    -        console.log("internal network access is blocked")
    -        }
    -        else{
    -           const response = await fetch('http://'+parsed.resource+parsed.pathname);
    -                console.log(response)
    -         }
    -        
    -

    Remediation

    -

    Upgrade parse-url to version 8.1.0 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Improper Input Validation

    +
    +

    Denial of Service (DoS)

    -
    - medium severity +
    + high severity

    • - Package Manager: npm + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod
    • - Vulnerable module: - - parse-url -
    • - -
    • Introduced through: - - - argo-cd-ui@1.0.0, git-url-parse@11.6.0 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - argo-cd-ui@1.0.0 - - git-url-parse@11.6.0 - - git-up@4.0.5 - - parse-url@6.0.5 - - - -
    • -
    - -
    - -
    - -

    Overview

    -

    parse-url is an An advanced url parser supporting git urls too.

    -

    Affected versions of this package are vulnerable to Improper Input Validation due to incorrect parsing of URLs. This allows the attacker to craft a malformed URL which can lead to a phishing attack.

    -
    
    -        const parseUrl = require("parse-url");
    -        const Url = require("url");
    -        
    -        const express = require('express');
    -        const app = express();
    -        
    -        var url = "https://www.google.com:x@fakesite.com:x";
    -        parsed = parseUrl(url);
    -        console.log("[*]`parse-url` output: ")
    -        console.log(parsed);
    -        
    -        parsed2 = Url.parse(url);
    -        console.log("[*]`url` output: ")
    -        console.log(parsed2)
    -        
    -        app.get('/', (req, res) => {
    -            if (parsed.host == "www.google.com") {
    -                res.send("<a href=\'" + parsed2.href + "\'>CLICK ME!</a>")
    -            }
    -        })
    -        
    -        app.listen(8888,"0.0.0.0");
    -        
    -

    Remediation

    -

    Upgrade parse-url to version 8.1.0 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Regular Expression Denial of Service (ReDoS)

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: npm + Package Manager: golang
    • Vulnerable module: - minimatch + google.golang.org/grpc
    • Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 and google.golang.org/grpc@1.56.2 - argo-cd-ui@1.0.0, redoc@2.0.0-rc.64 and others
    @@ -687,141 +515,20 @@

    Detailed paths

    • Introduced through: - argo-cd-ui@1.0.0 - - redoc@2.0.0-rc.64 - - @redocly/openapi-core@1.0.0-beta.82 + github.com/argoproj/argo-cd/v2@0.0.0 - minimatch@3.0.4 + google.golang.org/grpc@1.56.2
    • -
    - -
    - -
    - -

    Overview

    -

    minimatch is a minimal matching utility.

    -

    Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) via the braceExpand function in minimatch.js.

    -

    Details

    -

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.

    -

    The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.

    -

    Let’s take the following regular expression as an example:

    -
    regex = /A(B|C+)+D/
    -        
    -

    This regular expression accomplishes the following:

    -
      -
    • A The string must start with the letter 'A'
    • -
    • (B|C+)+ The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the + matches one or more times). The + at the end of this section states that we can look for one or more matches of this section.
    • -
    • D Finally, we ensure this section of the string ends with a 'D'
    • -
    -

    The expression would match inputs such as ABBD, ABCCCCD, ABCBCCCD and ACCCCCD

    -

    It most cases, it doesn't take very long for a regex engine to find a match:

    -
    $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
    -        0.04s user 0.01s system 95% cpu 0.052 total
    -        
    -        $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
    -        1.79s user 0.02s system 99% cpu 1.812 total
    -        
    -

    The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.

    -

    Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.

    -

    Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:

    -
      -
    1. CCC
    2. -
    3. CC+C
    4. -
    5. C+CC
    6. -
    7. C+C+C.
    8. -
    -

    The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.

    -

    From there, the number of steps the engine must use to validate a string just continues to grow.

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    StringNumber of C'sNumber of steps
    ACCCX338
    ACCCCX471
    ACCCCCX5136
    ACCCCCCCCCCCCCCX1465,553
    -

    By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.

    -

    Remediation

    -

    Upgrade minimatch to version 3.0.5 or higher.

    -

    References

    - - -
    - - - -
    -
    -

    Denial of Service (DoS)

    -
    - -
    - medium severity -
    - -
    - -
      -
    • - Package Manager: golang -
    • -
    • - Vulnerable module: - - golang.org/x/net/http2 -
    • - -
    • Introduced through: - - - github.com/argoproj/argo-cd/v2@0.0.0, k8s.io/client-go/rest@0.23.1 and others -
    • -
    - -
    - - -

    Detailed paths

    - -
    • Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -830,9 +537,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -841,9 +548,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -852,9 +559,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/soheilhy/cmux@0.1.5 + google.golang.org/grpc/health@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -863,11 +570,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/cache@0.23.1 - - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/reflection@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -876,11 +581,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/discovery@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -889,11 +592,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/dynamic@0.23.1 - - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -902,11 +603,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/transport/spdy@0.23.1 - - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -915,11 +614,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/pkg/kubeclientmetrics@#36c59d8fafe0 - - k8s.io/client-go/rest@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -928,11 +625,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/testing@0.23.1 - - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -941,11 +636,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/kubernetes@0.23.1 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.42.0 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -954,11 +647,11 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/azure@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -967,11 +660,11 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/gcp@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - k8s.io/client-go/rest@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlpconfig@1.16.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -980,11 +673,11 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/oidc@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - k8s.io/client-go/rest@0.23.1 + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -993,11 +686,11 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/record@0.23.1 + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -1006,11 +699,11 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/reflection@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -1019,11 +712,11 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/health@1.56.2 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -1032,13 +725,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 - k8s.io/client-go/discovery@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -1047,13 +740,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/listers/core/v1@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 - k8s.io/client-go/tools/cache@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -1062,13 +755,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/api@#567361917320 + 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 - k8s.io/client-go/tools/cache@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -1077,13 +772,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/informers/core/v1@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 + + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 - k8s.io/client-go/tools/cache@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.11.3 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc@1.56.2 @@ -1092,43 +789,164 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/informers@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 - k8s.io/client-go/tools/cache@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - golang.org/x/net/http2@#9d032be2e588 + 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

    + + +
    + + + +
    +
    +

    LGPL-3.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + 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 - k8s.io/client-go/tools/clientcmd@0.23.1 - - k8s.io/client-go/tools/auth@0.23.1 + github.com/Azure/kubelogin/pkg/token@0.0.20 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + gopkg.in/retry.v1@1.0.3
    • +
    + +
    + +
    + +

    LGPL-3.0 license

    + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/internal/encoding/json +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
    • Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/controller@#567361917320 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/client-go/tools/cache@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1137,13 +955,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/discovery/fake@0.23.1 + github.com/argoproj/pkg/grpc/http@#d56162821bd1 + + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/client-go/testing@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1152,13 +972,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/kubernetes/fake@0.23.1 + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/testing@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1167,13 +989,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/remotecommand@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - k8s.io/client-go/transport/spdy@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.56.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1182,13 +1008,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 + + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1197,13 +1027,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/rest@0.23.1 + 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 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1212,13 +1046,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc@1.56.2 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/transport@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.56.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1227,13 +1065,17 @@

      Detailed paths

      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-prometheus@1.2.0 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/pretty@1.56.2 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1242,13 +1084,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/grpc-ecosystem/go-grpc-middleware/retry@1.3.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 + + google.golang.org/grpc@1.56.2 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/transport@1.56.2 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1257,13 +1103,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 + + google.golang.org/grpc@1.56.2 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/transport@1.56.2 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1272,13 +1122,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - google.golang.org/grpc/health/grpc_health_v1@1.45.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@1.45.0 + google.golang.org/grpc/internal/transport@1.56.2 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1287,28 +1141,19 @@

      Detailed paths

      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.45.0 + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - golang.org/x/net/http2@#9d032be2e588 - - - -
    • -
    • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + google.golang.org/grpc@1.56.2 - github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + google.golang.org/grpc/internal/transport@1.56.2 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/pretty@1.56.2 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1317,28 +1162,19 @@

      Detailed paths

      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/reflection@1.56.2 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.56.2 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc@1.56.2 - golang.org/x/net/http2@#9d032be2e588 - - - -
    • -
    • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 - - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.6.3 + google.golang.org/grpc/internal/transport@1.56.2 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/pretty@1.56.2 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/protobuf/encoding/protojson@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1347,15 +1183,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/cache@0.7.3 + google.golang.org/grpc/health@1.56.2 + + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 + + google.golang.org/protobuf/internal/encoding/json@1.31.0 @@ -1364,83 +1204,98 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync@0.7.3 + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 - k8s.io/client-go/discovery@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - k8s.io/client-go/rest@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - golang.org/x/net/http2@#9d032be2e588 - - - -
    • -
    • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 + google.golang.org/grpc@1.56.2 - github.com/argoproj/gitops-engine/pkg/utils/kube@0.7.3 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/protobuf/encoding/protojson@1.31.0 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/internal/encoding/json@1.31.0 -
    • -
    • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 - - github.com/argoproj/notifications-engine/pkg/cmd@#567361917320 - - k8s.io/client-go/tools/clientcmd@0.23.1 - - k8s.io/client-go/tools/auth@0.23.1 - - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 - - +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/internal/encoding/json to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Stack-based Buffer Overflow

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + -
    • -
    • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 - - k8s.io/kubectl/pkg/util/term@0.23.1 - - k8s.io/client-go/tools/remotecommand@0.23.1 - - k8s.io/client-go/transport/spdy@0.23.1 - - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 - - + github.com/argoproj/argo-cd/v2@0.0.0, github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 and others +
    • +
    - +
    + + +

    Detailed paths

    + +
    • Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 - - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/apimachinery/pkg/watch@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1449,15 +1304,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/api/rbac/v1@0.23.1 - - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/argoproj/pkg/grpc/http@#d56162821bd1 - k8s.io/apimachinery/pkg/watch@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1466,15 +1319,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1483,15 +1334,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - sigs.k8s.io/controller-runtime/pkg/scheme@0.11.0 - - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - k8s.io/apimachinery/pkg/watch@0.23.1 + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.11.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1500,15 +1349,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/api/core/v1@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1517,15 +1366,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/api/errors@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1534,15 +1383,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/api/equality@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1551,15 +1400,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/discovery@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1568,15 +1417,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/dynamic@0.23.1 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1585,15 +1434,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/transport/spdy@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1602,15 +1451,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/pkg/kubeclientmetrics@#36c59d8fafe0 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1619,15 +1468,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/testing@0.23.1 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.42.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1636,15 +1485,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/kubernetes@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1653,15 +1502,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/azure@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - k8s.io/client-go/rest@0.23.1 + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 - k8s.io/client-go/transport@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.11.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/protobuf/types/known/structpb@1.31.0 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1670,15 +1519,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/gcp@0.23.1 + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 + + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1687,15 +1538,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/plugin/pkg/client/auth/oidc@0.23.1 + google.golang.org/grpc/reflection@1.56.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.56.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1704,15 +1557,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - google.golang.org/grpc/reflection@1.45.0 + google.golang.org/grpc/health@1.56.2 + + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.45.0 + google.golang.org/grpc@1.56.2 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/transport@1.56.2 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1721,15 +1576,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - google.golang.org/grpc/health@1.45.0 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - google.golang.org/grpc/health/grpc_health_v1@1.45.0 + google.golang.org/grpc@1.56.2 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/transport@1.56.2 - google.golang.org/grpc/internal/transport@1.45.0 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1738,17 +1595,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/health@0.7.3 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - github.com/argoproj/gitops-engine/pkg/utils/kube@0.7.3 + google.golang.org/grpc@1.56.2 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/client-go/rest@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1757,17 +1614,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/common@0.7.3 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 - github.com/argoproj/gitops-engine/pkg/utils/kube@0.7.3 + google.golang.org/grpc@1.56.2 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/client-go/rest@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1776,17 +1633,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - sigs.k8s.io/controller-runtime/pkg/controller/controllerutil@0.11.0 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 - sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/restmapper@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/client-go/rest@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1795,17 +1652,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - sigs.k8s.io/controller-runtime/pkg/envtest@0.11.0 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 - sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane@0.11.0 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/tools/clientcmd@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/tools/auth@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/client-go/rest@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1814,17 +1671,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1833,17 +1690,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/util/managedfields@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1852,17 +1709,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/common@0.7.3 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.42.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1871,17 +1728,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/hook@0.7.3 + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1890,17 +1749,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/resource@0.7.3 + google.golang.org/grpc/reflection@1.56.2 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1909,17 +1770,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/ignore@0.7.3 + google.golang.org/grpc/health@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + github.com/golang/protobuf/jsonpb@1.4.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1928,17 +1791,21 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/syncwaves@0.7.3 + 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 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/grpc/internal/pretty@1.56.2 + + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -1947,55 +1814,95 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/utils/testing@0.7.3 - - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 - k8s.io/apimachinery/pkg/watch@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - golang.org/x/net/http2@#9d032be2e588 - - - -
    • -
    • - Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0 - - k8s.io/client-go/tools/record@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/tools/reference@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Stack-based Buffer Overflow when processing input that uses pathologically deep nesting.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.32.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
    • Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/cache@0.23.1 - - k8s.io/client-go/tools/pager@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/apimachinery/pkg/watch@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2004,17 +1911,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/pkg/apis/clientauthentication/v1beta1@0.23.1 - - k8s.io/client-go/pkg/apis/clientauthentication@0.23.1 - - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + github.com/argoproj/pkg/grpc/http@#d56162821bd1 - k8s.io/apimachinery/pkg/watch@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/runtime@1.16.0 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2023,17 +1926,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - sigs.k8s.io/controller-runtime@0.11.0 + google.golang.org/grpc@1.56.2 - sigs.k8s.io/controller-runtime/pkg/scheme@0.11.0 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2042,17 +1941,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/util/retry@0.23.1 - - k8s.io/apimachinery/pkg/api/errors@0.23.1 - - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - k8s.io/apimachinery/pkg/watch@0.23.1 + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.11.3 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2061,17 +1956,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/kubectl/pkg/util/resource@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - k8s.io/api/core/v1@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2080,17 +1973,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/health@0.7.3 - - k8s.io/kubectl/pkg/util/podutils@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2099,17 +1990,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/api/validation@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1/validation@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2118,17 +2007,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/portforward@0.23.1 - - k8s.io/api/core/v1@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2137,17 +2024,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/discovery/fake@0.23.1 - - k8s.io/client-go/testing@0.23.1 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2156,17 +2041,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/kubernetes/fake@0.23.1 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - k8s.io/client-go/testing@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2175,17 +2058,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/remotecommand@0.23.1 - - k8s.io/client-go/transport/spdy@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2194,17 +2075,15 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.3.0 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.42.0 - github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + google.golang.org/grpc@1.56.2 - github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + google.golang.org/grpc/internal/transport@1.56.2 - google.golang.org/grpc@1.45.0 + google.golang.org/grpc/internal/pretty@1.56.2 - google.golang.org/grpc/internal/transport@1.45.0 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2213,19 +2092,15 @@

      Detailed paths

      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 + google.golang.org/grpc@1.56.2 - sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/restmapper@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/client-go/discovery@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2234,19 +2109,15 @@

      Detailed paths

      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 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 - k8s.io/client-go/restmapper@0.23.1 + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.11.3 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/protobuf/types/known/structpb@1.31.0 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2255,19 +2126,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/cache@0.7.3 - - k8s.io/kubectl/pkg/util/openapi@0.23.1 + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2276,19 +2145,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync@0.7.3 + google.golang.org/grpc/reflection@1.56.2 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.56.2 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2297,19 +2164,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/utils/kube@0.7.3 - - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc/health@1.56.2 - k8s.io/client-go/discovery@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2318,19 +2183,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/apimachinery/pkg/runtime/serializer@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2339,19 +2202,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/listers/core/v1@0.23.1 - - k8s.io/client-go/tools/cache@0.23.1 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - k8s.io/client-go/tools/pager@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2360,19 +2221,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/api@#567361917320 + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 - k8s.io/client-go/tools/cache@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/tools/pager@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2381,19 +2240,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/informers/core/v1@0.23.1 - - k8s.io/client-go/tools/cache@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 - k8s.io/client-go/tools/pager@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2402,19 +2259,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/informers@0.23.1 - - k8s.io/client-go/tools/cache@0.23.1 + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 - k8s.io/client-go/tools/pager@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2423,19 +2278,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/controller@#567361917320 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 - k8s.io/client-go/tools/cache@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/tools/pager@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2444,19 +2297,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/kubectl/pkg/util/term@0.23.1 - - k8s.io/client-go/tools/remotecommand@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 - k8s.io/client-go/transport/spdy@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/client-go/rest@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/transport@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2465,21 +2316,17 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/hook@0.7.3 + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.42.0 - github.com/argoproj/gitops-engine/pkg/sync/hook/helm@0.7.3 + google.golang.org/grpc@1.56.2 - github.com/argoproj/gitops-engine/pkg/sync/common@0.7.3 + google.golang.org/grpc/internal/transport@1.56.2 - github.com/argoproj/gitops-engine/pkg/utils/kube@0.7.3 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/client-go/discovery@0.23.1 - - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2488,21 +2335,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/syncwaves@0.7.3 + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 - github.com/argoproj/gitops-engine/pkg/sync/hook/helm@0.7.3 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - github.com/argoproj/gitops-engine/pkg/sync/common@0.7.3 + google.golang.org/grpc@1.56.2 - github.com/argoproj/gitops-engine/pkg/utils/kube@0.7.3 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/kubectl/pkg/util/openapi@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/client-go/discovery@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2511,21 +2356,19 @@

      Detailed paths

      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 + google.golang.org/grpc/reflection@1.56.2 - sigs.k8s.io/controller-runtime/pkg/webhook@0.11.0 + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.56.2 - sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics@0.11.0 + google.golang.org/grpc@1.56.2 - sigs.k8s.io/controller-runtime/pkg/metrics@0.11.0 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/tools/cache@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/client-go/rest@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2534,21 +2377,19 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + google.golang.org/grpc/health@1.56.2 - sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + google.golang.org/grpc/health/grpc_health_v1@1.56.2 - sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + google.golang.org/grpc@1.56.2 - sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/client-go/restmapper@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/client-go/discovery@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2557,21 +2398,21 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/kubernetes/scheme@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 - k8s.io/apimachinery/pkg/runtime/serializer@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 - k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0 @@ -2580,44 +2421,94 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/tools/clientcmd@0.23.1 + 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 - k8s.io/client-go/tools/clientcmd/api/latest@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 - k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.23.1 + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + google.golang.org/grpc@1.56.2 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + google.golang.org/grpc/internal/transport@1.56.2 - k8s.io/apimachinery/pkg/watch@0.23.1 + google.golang.org/grpc/internal/pretty@1.56.2 - k8s.io/apimachinery/pkg/util/net@0.23.1 + github.com/golang/protobuf/jsonpb@1.4.2 - golang.org/x/net/http2@#9d032be2e588 + google.golang.org/protobuf/encoding/protojson@1.31.0
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Authentication Bypass by Capture-replay

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/crypto/ssh +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@0.0.0 and golang.org/x/crypto/ssh@0.16.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
    • 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.23.1 - - k8s.io/client-go/discovery@0.23.1 - - k8s.io/client-go/rest@0.23.1 - - k8s.io/client-go/transport@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2626,23 +2517,9 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/sync/ignore@0.7.3 - - github.com/argoproj/gitops-engine/pkg/sync/hook@0.7.3 - - github.com/argoproj/gitops-engine/pkg/sync/hook/helm@0.7.3 - - github.com/argoproj/gitops-engine/pkg/sync/common@0.7.3 - - github.com/argoproj/gitops-engine/pkg/utils/kube@0.7.3 - - k8s.io/kubectl/pkg/util/openapi@0.23.1 + golang.org/x/crypto/ssh/knownhosts@0.16.0 - k8s.io/client-go/discovery@0.23.1 - - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2651,23 +2528,9 @@

      Detailed paths

      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/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.23.1 - - k8s.io/client-go/discovery@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/rest@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2676,23 +2539,11 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/gitops-engine/pkg/diff@0.7.3 - - k8s.io/client-go/kubernetes/scheme@0.23.1 - - k8s.io/apimachinery/pkg/runtime/serializer@0.23.1 - - k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + github.com/skeema/knownhosts@1.2.1 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 - - k8s.io/apimachinery/pkg/watch@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2701,23 +2552,11 @@

      Detailed paths

      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 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/apimachinery/pkg/runtime/serializer@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.23.1 - - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 - - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 - - k8s.io/apimachinery/pkg/watch@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2726,23 +2565,13 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/cmd@#567361917320 - - k8s.io/client-go/tools/clientcmd@0.23.1 - - k8s.io/client-go/tools/clientcmd/api/latest@0.23.1 - - k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.23.1 + github.com/skeema/knownhosts@1.2.1 - k8s.io/apimachinery/pkg/apis/meta/v1@0.23.1 + golang.org/x/crypto/ssh/knownhosts@0.16.0 - k8s.io/apimachinery/pkg/watch@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2751,23 +2580,13 @@

      Detailed paths

      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 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/client-go/restmapper@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/discovery@0.23.1 + github.com/skeema/knownhosts@1.2.1 - k8s.io/client-go/rest@0.23.1 - - k8s.io/client-go/transport@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2776,23 +2595,13 @@

      Detailed paths

      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 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + github.com/xanzy/ssh-agent@0.3.3 - k8s.io/client-go/restmapper@0.23.1 + golang.org/x/crypto/ssh/agent@0.16.0 - k8s.io/client-go/discovery@0.23.1 - - k8s.io/client-go/rest@0.23.1 - - k8s.io/client-go/transport@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2801,25 +2610,13 @@

      Detailed paths

      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.23.1 + github.com/go-git/go-git/v5@5.11.0 - k8s.io/client-go/discovery@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/client-go/rest@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/transport@0.23.1 - - k8s.io/apimachinery/pkg/util/net@0.23.1 - - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2828,27 +2625,15 @@

      Detailed paths

      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 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/client-go/restmapper@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/discovery@0.23.1 + github.com/skeema/knownhosts@1.2.1 - k8s.io/client-go/rest@0.23.1 + golang.org/x/crypto/ssh/knownhosts@0.16.0 - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2857,27 +2642,32 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - sigs.k8s.io/controller-runtime/pkg/handler@0.11.0 + github.com/go-git/go-git/v5@5.11.0 - sigs.k8s.io/controller-runtime/pkg/runtime/inject@0.11.0 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + github.com/skeema/knownhosts@1.2.1 - sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 - - k8s.io/client-go/restmapper@0.23.1 + golang.org/x/crypto/ssh@0.16.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/discovery@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/client-go/rest@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/transport@0.23.1 + github.com/xanzy/ssh-agent@0.3.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + golang.org/x/crypto/ssh/agent@0.16.0 - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2886,31 +2676,36 @@

      Detailed paths

      Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - sigs.k8s.io/controller-runtime/pkg/source@0.11.0 + github.com/go-git/go-git/v5@5.11.0 - sigs.k8s.io/controller-runtime/pkg/source/internal@0.11.0 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + github.com/skeema/knownhosts@1.2.1 - sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + golang.org/x/crypto/ssh/knownhosts@0.16.0 - sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 - - sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + golang.org/x/crypto/ssh@0.16.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 - k8s.io/client-go/restmapper@0.23.1 + github.com/go-git/go-git/v5@5.11.0 - k8s.io/client-go/discovery@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/client@5.11.0 - k8s.io/client-go/rest@0.23.1 + github.com/go-git/go-git/v5/plumbing/transport/ssh@5.11.0 - k8s.io/client-go/transport@0.23.1 + github.com/xanzy/ssh-agent@0.3.3 - k8s.io/apimachinery/pkg/util/net@0.23.1 + golang.org/x/crypto/ssh/agent@0.16.0 - golang.org/x/net/http2@#9d032be2e588 + golang.org/x/crypto/ssh@0.16.0 @@ -2922,39 +2717,49 @@

      Detailed paths


      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) due to improper checks and limitations for the number of entries in the cache, which can allow an attacker to consume unbounded amounts of memory by sending a small number of very large keys.

      -

      Details

      -

      Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

      -

      Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

      -

      One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

      -

      When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

      -

      Two common types of DoS vulnerabilities:

      -
        -
      • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

        +

        golang.org/x/crypto/ssh is a SSH client and server

        +

        Affected versions of this package are vulnerable to Authentication Bypass by Capture-replay during the establishment of the secure channel. An attacker can manipulate handshake sequence numbers to delete messages sent immediately after the channel is established.

        +

        Note:

        +
          +
        1. Sequence numbers are only validated once the channel is established and arbitrary messages are allowed during the handshake, allowing them to manipulate the sequence numbers.

        2. -
        3. Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

          +
        4. The potential consequences of the general Terrapin attack are dependent on the messages exchanged after the handshake concludes. If you are using a custom SSH service and do not resort to the authentication protocol, you should check that dropping the first few messages of a connection does not yield security risks.

        5. -
      + +

      Impact:

      +

      While cryptographically novel, there is no discernable impact on the integrity of SSH traffic beyond giving the attacker the ability to delete the message that enables some features related to keystroke timing obfuscation. To successfully carry out the exploitation, the connection needs to be protected using either the ChaCha20-Poly1305 or CBC with Encrypt-then-MAC encryption methods. The attacker must also be able to intercept and modify the connection's traffic.

      +

      Workaround

      +

      Temporarily disable the affected chacha20-poly1305@openssh.com encryption and *-etm@openssh.com MAC algorithms in the affected configuration, and use unaffected algorithms like AES-GCM instead.

      Remediation

      -

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

      +

      Upgrade golang.org/x/crypto/ssh to version 0.17.0 or higher.

      References


    -

    Improper Input Validation

    +

    MPL-2.0 license

    @@ -2964,19 +2769,22 @@

    Improper Input Validation


      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • Package Manager: golang
    • - Vulnerable module: + Module: - go.mongodb.org/mongo-driver/bson/bsonrw + github.com/r3labs/diff
    • Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 and github.com/r3labs/diff@1.1.0 - github.com/argoproj/argo-cd/v2@0.0.0, github.com/go-openapi/runtime/middleware@0.19.4 and others
    @@ -2990,34 +2798,69 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/go-openapi/runtime/middleware@0.19.4 - - github.com/go-openapi/validate@0.19.5 - - github.com/go-openapi/strfmt@0.19.3 - - go.mongodb.org/mongo-driver/bson@1.1.2 - - go.mongodb.org/mongo-driver/bson/bsonrw@1.1.2 + github.com/r3labs/diff@1.1.0 + + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + 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 - github.com/go-openapi/runtime/middleware@0.19.4 - - github.com/go-openapi/validate@0.19.5 + code.gitea.io/sdk/gitea@0.15.1 - github.com/go-openapi/strfmt@0.19.3 - - go.mongodb.org/mongo-driver/bson@1.1.2 - - go.mongodb.org/mongo-driver/bson/bsoncodec@1.1.2 - - go.mongodb.org/mongo-driver/bson/bsonrw@1.1.2 + github.com/hashicorp/go-version@1.2.1 @@ -3028,27 +2871,17 @@

      Detailed paths


      -

      Overview

      -

      go.mongodb.org/mongo-driver/bson/bsonrw is a The MongoDB supported driver for Go.

      -

      Affected versions of this package are vulnerable to Improper Input Validation. Specific cstrings input may not be properly validated in the MongoDB Go Driver when marshalling Go objects into BSON. A malicious user could use a Go object with specific string to potentially inject additional fields into marshalled documents.

      -

      Remediation

      -

      Upgrade go.mongodb.org/mongo-driver/bson/bsonrw to version 1.5.1 or higher.

      -

      References

      - +

      MPL-2.0 license


    -

    Insecure Randomness

    +

    MPL-2.0 license

    @@ -3058,19 +2891,22 @@

    Insecure Randomness


      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • Package Manager: golang
    • - Vulnerable module: + Module: - github.com/Masterminds/goutils + 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 - github.com/argoproj/argo-cd/v2@0.0.0, github.com/argoproj/notifications-engine/pkg/api@#567361917320 and others
    @@ -3084,13 +2920,61 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/api@#567361917320 + 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/templates@#567361917320 + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf - github.com/Masterminds/sprig@2.22.0 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-retryablehttp@0.7.4 @@ -3099,15 +2983,15 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/cmd@#567361917320 + github.com/argoproj/notifications-engine/pkg/api@#9dcecdc3eebf - github.com/argoproj/notifications-engine/pkg/api@#567361917320 + github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf - github.com/argoproj/notifications-engine/pkg/templates@#567361917320 + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf - github.com/Masterminds/sprig@2.22.0 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-retryablehttp@0.7.4 @@ -3116,15 +3000,15 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/controller@#567361917320 + github.com/argoproj/notifications-engine/pkg/controller@#9dcecdc3eebf - github.com/argoproj/notifications-engine/pkg/api@#567361917320 + github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf - github.com/argoproj/notifications-engine/pkg/templates@#567361917320 + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf - github.com/Masterminds/sprig@2.22.0 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-retryablehttp@0.7.4 @@ -3135,25 +3019,17 @@

    Detailed paths


    -

    Overview

    -

    github.com/masterminds/goutils is a provides users with utility functions to manipulate strings in various ways.

    -

    Affected versions of this package are vulnerable to Insecure Randomness via the RandomAlphaNumeric(int) and CryptoRandomAlphaNumeric(int) functions. Small values of int in the functions above will return a smaller subset of results than they should. For example, RandomAlphaNumeric(1) would always return a digit in the 0-9 range, while RandomAlphaNumeric(4) return around ~7 million of the ~13M possible permutations.

    -

    Remediation

    -

    Upgrade github.com/masterminds/goutils to version 1.1.1 or higher.

    -

    References

    - +

    MPL-2.0 license


  • -

    Insecure Randomness

    +

    MPL-2.0 license

    @@ -3163,19 +3039,22 @@

    Insecure Randomness


      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • Package Manager: golang
    • - Vulnerable module: + Module: - github.com/Masterminds/goutils + github.com/hashicorp/go-cleanhttp
    • Introduced through: - github.com/argoproj/argo-cd/v2@0.0.0, github.com/argoproj/notifications-engine/pkg/api@#567361917320 and others + github.com/argoproj/argo-cd/v2@0.0.0, github.com/hashicorp/go-retryablehttp@0.7.4 and others
    @@ -3189,13 +3068,82 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/api@#567361917320 + 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/templates@#567361917320 + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf - github.com/Masterminds/sprig@2.22.0 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-retryablehttp@0.7.4 + + github.com/hashicorp/go-cleanhttp@0.5.2 @@ -3204,15 +3152,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/cmd@#567361917320 + github.com/argoproj/notifications-engine/pkg/api@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf - github.com/argoproj/notifications-engine/pkg/api@#567361917320 + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf - github.com/argoproj/notifications-engine/pkg/templates@#567361917320 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/sprig@2.22.0 + github.com/hashicorp/go-retryablehttp@0.7.4 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-cleanhttp@0.5.2 @@ -3221,15 +3171,17 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/controller@#567361917320 + github.com/argoproj/notifications-engine/pkg/controller@#9dcecdc3eebf - github.com/argoproj/notifications-engine/pkg/api@#567361917320 + github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf - github.com/argoproj/notifications-engine/pkg/templates@#567361917320 + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf - github.com/Masterminds/sprig@2.22.0 + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 - github.com/Masterminds/goutils@1.1.0 + github.com/hashicorp/go-retryablehttp@0.7.4 + + github.com/hashicorp/go-cleanhttp@0.5.2 @@ -3240,25 +3192,77 @@

    Detailed paths


    -

    Overview

    -

    github.com/masterminds/goutils is a provides users with utility functions to manipulate strings in various ways.

    -

    Affected versions of this package are vulnerable to Insecure Randomness when randomly-generated alphanumeric strings contain significantly less entropy than expected, the RandomAlphaNumeric and CryptoRandomAlphaNumeric functions always return strings containing at least one digit from 0 to 9. This significantly reduces the amount of entropy in short strings generated by these functions.

    -

    Remediation

    -

    Upgrade github.com/masterminds/goutils to version 1.1.1 or higher.

    -

    References

    - +

    MPL-2.0 license

    + +
    + + + +
  • +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + 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


    -

    Regular Expression Denial of Service (ReDoS)

    +

    Improper Handling of Highly Compressed Data (Data Amplification)

    @@ -3269,18 +3273,21 @@

    Regular Expression Denial of Service (ReDoS)

    • - Package Manager: npm + Manifest file: /argo-cd/argoproj/argo-cd/v2 go.mod +
    • +
    • + Package Manager: golang
    • Vulnerable module: - cookiejar + github.com/go-jose/go-jose/v3
    • Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 and github.com/go-jose/go-jose/v3@3.0.1 - argo-cd-ui@1.0.0, superagent@7.1.3 and others
    @@ -3292,11 +3299,20 @@

    Detailed paths

    • Introduced through: - argo-cd-ui@1.0.0 + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/go-jose/go-jose/v3@3.0.1 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 - superagent@7.1.3 + github.com/coreos/go-oidc/v3/oidc@3.6.0 - cookiejar@2.1.3 + github.com/go-jose/go-jose/v3@3.0.1 @@ -3308,91 +3324,20 @@

      Detailed paths


      Overview

      -

      Affected versions of this package are vulnerable to Regular Expression Denial of Service (ReDoS) via the Cookie.parse function, which uses an insecure regular expression.

      -

      PoC

      -
      const { CookieJar } = require("cookiejar");
      -        
      -        const jar = new CookieJar();
      -        
      -        const start = performance.now();
      -        const attack = "a" + "t".repeat(50_000);
      -        jar.setCookie(attack);
      -        console.log(`CookieJar.setCookie(): ${performance.now() - start}`);
      -        
      -

      Details

      -

      Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its original and legitimate users. There are many types of DoS attacks, ranging from trying to clog the network pipes to the system by generating a large volume of traffic from many machines (a Distributed Denial of Service - DDoS - attack) to sending crafted requests that cause a system to crash or take a disproportional amount of time to process.

      -

      The Regular expression Denial of Service (ReDoS) is a type of Denial of Service attack. Regular expressions are incredibly powerful, but they aren't very intuitive and can ultimately end up making it easy for attackers to take your site down.

      -

      Let’s take the following regular expression as an example:

      -
      regex = /A(B|C+)+D/
      -        
      -

      This regular expression accomplishes the following:

      -
        -
      • A The string must start with the letter 'A'
      • -
      • (B|C+)+ The string must then follow the letter A with either the letter 'B' or some number of occurrences of the letter 'C' (the + matches one or more times). The + at the end of this section states that we can look for one or more matches of this section.
      • -
      • D Finally, we ensure this section of the string ends with a 'D'
      • -
      -

      The expression would match inputs such as ABBD, ABCCCCD, ABCBCCCD and ACCCCCD

      -

      It most cases, it doesn't take very long for a regex engine to find a match:

      -
      $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCD")'
      -        0.04s user 0.01s system 95% cpu 0.052 total
      -        
      -        $ time node -e '/A(B|C+)+D/.test("ACCCCCCCCCCCCCCCCCCCCCCCCCCCCX")'
      -        1.79s user 0.02s system 99% cpu 1.812 total
      -        
      -

      The entire process of testing it against a 30 characters long string takes around ~52ms. But when given an invalid string, it takes nearly two seconds to complete the test, over ten times as long as it took to test a valid string. The dramatic difference is due to the way regular expressions get evaluated.

      -

      Most Regex engines will work very similarly (with minor differences). The engine will match the first possible way to accept the current character and proceed to the next one. If it then fails to match the next one, it will backtrack and see if there was another way to digest the previous character. If it goes too far down the rabbit hole only to find out the string doesn’t match in the end, and if many characters have multiple valid regex paths, the number of backtracking steps can become very large, resulting in what is known as catastrophic backtracking.

      -

      Let's look at how our expression runs into this problem, using a shorter string: "ACCCX". While it seems fairly straightforward, there are still four different ways that the engine could match those three C's:

      -
        -
      1. CCC
      2. -
      3. CC+C
      4. -
      5. C+CC
      6. -
      7. C+C+C.
      8. -
      -

      The engine has to try each of those combinations to see if any of them potentially match against the expression. When you combine that with the other steps the engine must take, we can use RegEx 101 debugger to see the engine has to take a total of 38 steps before it can determine the string doesn't match.

      -

      From there, the number of steps the engine must use to validate a string just continues to grow.

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      StringNumber of C'sNumber of steps
      ACCCX338
      ACCCCX471
      ACCCCCX5136
      ACCCCCCCCCCCCCCX1465,553
      -

      By the time the string includes 14 C's, the engine has to take over 65,000 steps just to see if the string is valid. These extreme situations can cause them to work very slowly (exponentially related to input size, as shown above), allowing an attacker to exploit this and can cause the service to excessively consume CPU, resulting in a Denial of Service.

      +

      Affected versions of this package are vulnerable to Improper Handling of Highly Compressed Data (Data Amplification). An attacker could send a JWE containing compressed data that, when decompressed by Decrypt or DecryptMulti, would use large amounts of memory and CPU.

      Remediation

      -

      Upgrade cookiejar to version 2.1.4 or higher.

      +

      Upgrade github.com/go-jose/go-jose/v3 to version 3.0.3 or higher.

      References


    diff --git a/docs/snyk/v2.9.9/ghcr.io_dexidp_dex_v2.37.0.html b/docs/snyk/v2.9.9/ghcr.io_dexidp_dex_v2.37.0.html new file mode 100644 index 0000000000000..ca1fb70c0e4b2 --- /dev/null +++ b/docs/snyk/v2.9.9/ghcr.io_dexidp_dex_v2.37.0.html @@ -0,0 +1,4337 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    March 24th 2024, 12:17:49 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//usr/local/bin/gomplate (gomodules)
    • +
    • ghcr.io/dexidp/dex:v2.37.0/dexidp/dex//usr/local/bin/docker-entrypoint (gomodules)
    • +
    • ghcr.io/dexidp/dex:v2.37.0/dexidp/dex//usr/local/bin/dex (gomodules)
    • +
    +
    + +
    +
    42 known vulnerabilities
    +
    121 vulnerable dependency paths
    +
    786 dependencies
    +
    +
    +
    +
    + +
    +
    +
    +

    Path Traversal

    +
    + +
    + critical severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-git/go-git/v5 +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/go-git/go-git/v5@v5.4.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/go-git/go-git/v5@v5.4.2 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Path Traversal via malicious server replies. An attacker can create and amend files across the filesystem and potentially achieve remote code execution by sending crafted responses to the client.

    +

    Notes:

    +
      +
    1. This is only exploitable if the client is using ChrootOS, which is the default for certain functions such as PlainClone.

      +
    2. +
    3. Applications using BoundOS or in-memory filesystems are not affected by this issue.

      +
    4. +
    5. Users running versions of go-git from v4 and above are recommended to upgrade to v5.11 in order to mitigate this vulnerability.

      +
    6. +
    +

    Workaround

    +

    This vulnerability can be mitigated by limiting the client's use to trustworthy Git servers.

    +

    Remediation

    +

    Upgrade github.com/go-git/go-git/v5 to version 5.11.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    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

    + + +
    + + + +
    +
    +

    CVE-2023-5363

    +
    + +
    + high 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

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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

    + + +
    + + + +
    +
    +

    Heap-based Buffer Overflow

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/mattn/go-sqlite3 +
    • + +
    • Introduced through: + + github.com/dexidp/dex@* and github.com/mattn/go-sqlite3@v1.14.17 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/mattn/go-sqlite3@v1.14.17 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Heap-based Buffer Overflow via the sessionReadRecord function in the ext/session/sqlite3session.c file. An attacker can cause a program crash or execute arbitrary code by manipulating the input to trigger a heap-based buffer overflow.

    +

    Remediation

    +

    Upgrade github.com/mattn/go-sqlite3 to version 1.14.18 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-jose/go-jose/v3 +
    • + +
    • Introduced through: + + github.com/dexidp/dex@* and github.com/go-jose/go-jose/v3@v3.0.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/go-jose/go-jose/v3@v3.0.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) when decrypting JWE inputs. An attacker can cause a denial-of-service by providing a PBES2 encrypted JWE blob with a very large p2c value.

    +

    Details

    +

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

    +

    Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

    +

    One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

    +

    When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

    +

    Two common types of DoS vulnerabilities:

    +
      +
    • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

      +
    • +
    • Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

      +
    • +
    +

    Remediation

    +

    Upgrade github.com/go-jose/go-jose/v3 to version 3.0.1 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. + 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

    + + +
    + + + +
    +
    +

    Improper Check for Unusual or Exceptional Conditions

    +
    + +
    + 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: Generating excessively long X9.42 DH keys or checking + excessively long X9.42 DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_generate_key() to + generate an X9.42 DH key may experience long delays. Likewise, applications + that use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check() + to check an X9.42 DH key or X9.42 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.

    +

    While DH_check() performs all the necessary checks (as of CVE-2023-3817), + DH_check_pub_key() doesn't make any of these checks, and is therefore + vulnerable for excessively large P and Q parameters.

    +

    Likewise, while DH_generate_key() performs a check for an excessively large + P, it doesn't check for an excessively large Q.

    +

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

    +

    DH_generate_key() and DH_check_pub_key() are also 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_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().

    +

    Also vulnerable are the OpenSSL pkey command line application when using the + "-pubcheck" option, as well as the OpenSSL genpkey command line application.

    +

    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.4-r1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + 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: The POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

    +

    Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

    +

    The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

    +

    The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

    +

    The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-0727

    +
    + +
    + 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: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

    +

    Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

    +

    A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

    +

    OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

    +

    We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

    +

    The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/internal/encoding/json +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/protobuf/internal/encoding/json@v1.28.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/protobuf/internal/encoding/json@v1.28.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/protobuf/internal/encoding/json@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/internal/encoding/json to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Stack-based Buffer Overflow

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/protobuf/encoding/protojson@v1.28.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/protobuf/encoding/protojson@v1.28.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Stack-based Buffer Overflow when processing input that uses pathologically deep nesting.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.32.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/protobuf/encoding/protojson@v1.28.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/protobuf/encoding/protojson@v1.28.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Allocation of Resources Without Limits or Throttling

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 Allocation of Resources Without Limits or Throttling when MaxConcurrentStreams handler goroutines running. A a handler is started until one of the existing handlers exits.

    +

    Note:

    +

    This issue is related to CVE-2023-44487

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    Cross-site Scripting (XSS)

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + 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

    + + +
    + + + +
    +
    +

    Authentication Bypass by Capture-replay

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/crypto/ssh +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and golang.org/x/crypto/ssh@v0.0.0-20220525230936-793ad666bf5e + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + golang.org/x/crypto/ssh@v0.0.0-20220525230936-793ad666bf5e + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/crypto/ssh is a SSH client and server

    +

    Affected versions of this package are vulnerable to Authentication Bypass by Capture-replay during the establishment of the secure channel. An attacker can manipulate handshake sequence numbers to delete messages sent immediately after the channel is established.

    +

    Note:

    +
      +
    1. Sequence numbers are only validated once the channel is established and arbitrary messages are allowed during the handshake, allowing them to manipulate the sequence numbers.

      +
    2. +
    3. The potential consequences of the general Terrapin attack are dependent on the messages exchanged after the handshake concludes. If you are using a custom SSH service and do not resort to the authentication protocol, you should check that dropping the first few messages of a connection does not yield security risks.

      +
    4. +
    +

    Impact:

    +

    While cryptographically novel, there is no discernable impact on the integrity of SSH traffic beyond giving the attacker the ability to delete the message that enables some features related to keystroke timing obfuscation. To successfully carry out the exploitation, the connection needs to be protected using either the ChaCha20-Poly1305 or CBC with Encrypt-then-MAC encryption methods. The attacker must also be able to intercept and modify the connection's traffic.

    +

    Workaround

    +

    Temporarily disable the affected chacha20-poly1305@openssh.com encryption and *-etm@openssh.com MAC algorithms in the affected configuration, and use unaffected algorithms like AES-GCM instead.

    +

    Remediation

    +

    Upgrade golang.org/x/crypto/ssh to version 0.17.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + 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

    + +
    + + + +
    +
    +

    Improper Handling of Highly Compressed Data (Data Amplification)

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/dexidp/dex /usr/local/bin/dex +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-jose/go-jose/v3 +
    • + +
    • Introduced through: + + github.com/dexidp/dex@* and github.com/go-jose/go-jose/v3@v3.0.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/go-jose/go-jose/v3@v3.0.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Improper Handling of Highly Compressed Data (Data Amplification). An attacker could send a JWE containing compressed data that, when decompressed by Decrypt or DecryptMulti, would use large amounts of memory and CPU.

    +

    Remediation

    +

    Upgrade github.com/go-jose/go-jose/v3 to version 3.0.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Uncontrolled Resource Consumption ('Resource Exhaustion')

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 /usr/local/bin/gomplate +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-git/go-git/v5/plumbing +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/go-git/go-git/v5/plumbing@v5.4.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/go-git/go-git/v5/plumbing@v5.4.2 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    github.com/go-git/go-git/v5/plumbing is a highly extensible git implementation library written in pure Go.

    +

    Affected versions of this package are vulnerable to Uncontrolled Resource Consumption ('Resource Exhaustion') via specially crafted responses from a Git server, which triggers resource exhaustion in clients.

    +

    Note + This is only exploitable if the client is not using the in-memory filesystem supported by the library.

    +

    Workaround

    +

    In cases where a bump to the latest version of go-git is not possible, we recommend limiting its use to only trust-worthy Git servers.

    +

    Details

    +

    Denial of Service (DoS) describes a family of attacks, all aimed at making a system inaccessible to its intended and legitimate users.

    +

    Unlike other vulnerabilities, DoS attacks usually do not aim at breaching security. Rather, they are focused on making websites and services unavailable to genuine users resulting in downtime.

    +

    One popular Denial of Service vulnerability is DDoS (a Distributed Denial of Service), an attack that attempts to clog network pipes to the system by generating a large volume of traffic from many machines.

    +

    When it comes to open source libraries, DoS vulnerabilities allow attackers to trigger such a crash or crippling of the service by using a flaw either in the application code or from the use of open source libraries.

    +

    Two common types of DoS vulnerabilities:

    +
      +
    • High CPU/Memory Consumption- An attacker sending crafted requests that could cause the system to take a disproportionate amount of time to process. For example, commons-fileupload:commons-fileupload.

      +
    • +
    • Crash - An attacker sending crafted requests that could cause the system to crash. For Example, npm ws package

      +
    • +
    +

    Remediation

    +

    Upgrade github.com/go-git/go-git/v5/plumbing to version 5.11.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-6237

    +
    + +
    + 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

    +

    This vulnerability has not been analyzed by NVD yet.

    +

    Remediation

    +

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

    + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.9.9/haproxy_2.6.14-alpine.html b/docs/snyk/v2.9.9/haproxy_2.6.14-alpine.html new file mode 100644 index 0000000000000..22d46e565dc6f --- /dev/null +++ b/docs/snyk/v2.9.9/haproxy_2.6.14-alpine.html @@ -0,0 +1,1376 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    March 24th 2024, 12:17:53 am (UTC+00:00)

    +
    +
    + Scanned the following path: +
      +
    • haproxy:2.6.14-alpine (apk)
    • +
    +
    + +
    +
    5 known vulnerabilities
    +
    45 vulnerable dependency paths
    +
    18 dependencies
    +
    +
    +
    +
    +
    + + + + + + + +
    Project docker-image|haproxy
    Path haproxy:2.6.14-alpine
    Package Manager apk
    +
    +
    +
    +
    +

    CVE-2023-5363

    +
    + +
    + high 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

    + + +
    + + + +
    +
    +

    Improper Check for Unusual or Exceptional Conditions

    +
    + +
    + medium 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: Generating excessively long X9.42 DH keys or checking + excessively long X9.42 DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_generate_key() to + generate an X9.42 DH key may experience long delays. Likewise, applications + that use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check() + to check an X9.42 DH key or X9.42 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.

    +

    While DH_check() performs all the necessary checks (as of CVE-2023-3817), + DH_check_pub_key() doesn't make any of these checks, and is therefore + vulnerable for excessively large P and Q parameters.

    +

    Likewise, while DH_generate_key() performs a check for an excessively large + P, it doesn't check for an excessively large Q.

    +

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

    +

    DH_generate_key() and DH_check_pub_key() are also 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_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().

    +

    Also vulnerable are the OpenSSL pkey command line application when using the + "-pubcheck" option, as well as the OpenSSL genpkey command line application.

    +

    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.4-r1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + medium 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: The POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

    +

    Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

    +

    The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

    +

    The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

    +

    The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-0727

    +
    + +
    + medium 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: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

    +

    Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

    +

    A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

    +

    OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

    +

    We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

    +

    The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-6237

    +
    + +
    + 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

    +

    This vulnerability has not been analyzed by NVD yet.

    +

    Remediation

    +

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

    + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.9.9/quay.io_argoproj_argocd_v2.9.9.html b/docs/snyk/v2.9.9/quay.io_argoproj_argocd_v2.9.9.html new file mode 100644 index 0000000000000..704d480d51ff7 --- /dev/null +++ b/docs/snyk/v2.9.9/quay.io_argoproj_argocd_v2.9.9.html @@ -0,0 +1,4812 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    March 24th 2024, 12:18:09 am (UTC+00:00)

    +
    +
    + Scanned the following paths: +
      +
    • quay.io/argoproj/argocd:v2.9.9/argoproj/argocd/Dockerfile (deb)
    • +
    • quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2//usr/local/bin/argocd (gomodules)
    • +
    • quay.io/argoproj/argocd:v2.9.9//usr/local/bin/kustomize (gomodules)
    • +
    • quay.io/argoproj/argocd:v2.9.9/helm/v3//usr/local/bin/helm (gomodules)
    • +
    • quay.io/argoproj/argocd:v2.9.9/git-lfs/git-lfs//usr/bin/git-lfs (gomodules)
    • +
    +
    + +
    +
    36 known vulnerabilities
    +
    179 vulnerable dependency paths
    +
    2189 dependencies
    +
    +
    +
    +
    + +
    +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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

    + + +
    + + + +
    +
    +

    CVE-2020-22916

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

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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.

    +

    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

    + + +
    + + + +
    +
    +

    CVE-2023-51767

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + openssh/openssh-client +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and openssh/openssh-client@1:8.9p1-3ubuntu0.6 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    OpenSSH through 9.6, when common types of DRAM are used, might allow row hammer attacks (for authentication bypass) because the integer value of authenticated in mm_answer_authpassword does not resist flips of a single bit. NOTE: this is applicable to a certain threat model of attacker-victim co-location in which the attacker has user privileges.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 openssh.

    +

    References

    + + +
    + + + +
    +
    +

    Information Exposure

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + libgcrypt20 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and libgcrypt20@1.9.4-3ubuntu3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + apt@2.4.11 + + gnupg2/gpgv@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpgsm@2.2.27-3ubuntu2.1 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + libgcrypt20@1.9.4-3ubuntu3 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    A timing-based side-channel flaw was found in libgcrypt's RSA implementation. This issue may allow a remote attacker to initiate a Bleichenbacher-style attack, which can lead to the decryption of RSA ciphertexts.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 libgcrypt20.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-26461

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and krb5/libk5crypto3@1.19.2-2ubuntu0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libkrb5support0@1.19.2-2ubuntu0.3 + + + +
    • +
    + +
    + +
    + +

    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.

    +

    Kerberos 5 (aka krb5) 1.21.2 contains a memory leak vulnerability in /krb5/src/lib/gssapi/krb5/k5sealv3.c.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-26462

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and krb5/libk5crypto3@1.19.2-2ubuntu0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libkrb5support0@1.19.2-2ubuntu0.3 + + + +
    • +
    + +
    + +
    + +

    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.

    +

    Kerberos 5 (aka krb5) 1.21.2 contains a memory leak vulnerability in /krb5/src/kdc/ndr.c.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-26458

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and krb5/libk5crypto3@1.19.2-2ubuntu0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libkrb5support0@1.19.2-2ubuntu0.3 + + + +
    • +
    + +
    + +
    + +

    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.

    +

    Kerberos 5 (aka krb5) 1.21.2 contains a memory leak in /krb5/src/lib/rpc/pmap_rmt.c.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    References

    + + +
    + + + +
    +
    +

    LGPL-3.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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

    + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/internal/encoding/json +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/protobuf/internal/encoding/json@v1.31.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + google.golang.org/protobuf/internal/encoding/json@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/internal/encoding/json to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Stack-based Buffer Overflow

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/protobuf/encoding/protojson@v1.31.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Stack-based Buffer Overflow when processing input that uses pathologically deep nesting.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.32.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Infinite loop

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/protobuf/encoding/protojson +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/protobuf/encoding/protojson@v1.31.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + google.golang.org/protobuf/encoding/protojson@v1.31.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Infinite loop via the protojson.Unmarshal function. An attacker can cause a denial of service condition by unmarshaling certain forms of invalid JSON.

    +

    Note:

    +

    This condition can occur when unmarshaling into a message which contains a google.protobuf.Any value, or when the UnmarshalOptions.DiscardUnknown option is set.

    +

    Remediation

    +

    Upgrade google.golang.org/protobuf/encoding/protojson to version 1.33.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Authentication Bypass by Capture-replay

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/crypto/ssh +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and golang.org/x/crypto/ssh@v0.16.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + golang.org/x/crypto/ssh@v0.16.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/crypto/ssh is a SSH client and server

    +

    Affected versions of this package are vulnerable to Authentication Bypass by Capture-replay during the establishment of the secure channel. An attacker can manipulate handshake sequence numbers to delete messages sent immediately after the channel is established.

    +

    Note:

    +
      +
    1. Sequence numbers are only validated once the channel is established and arbitrary messages are allowed during the handshake, allowing them to manipulate the sequence numbers.

      +
    2. +
    3. The potential consequences of the general Terrapin attack are dependent on the messages exchanged after the handshake concludes. If you are using a custom SSH service and do not resort to the authentication protocol, you should check that dropping the first few messages of a connection does not yield security risks.

      +
    4. +
    +

    Impact:

    +

    While cryptographically novel, there is no discernable impact on the integrity of SSH traffic beyond giving the attacker the ability to delete the message that enables some features related to keystroke timing obfuscation. To successfully carry out the exploitation, the connection needs to be protected using either the ChaCha20-Poly1305 or CBC with Encrypt-then-MAC encryption methods. The attacker must also be able to intercept and modify the connection's traffic.

    +

    Workaround

    +

    Temporarily disable the affected chacha20-poly1305@openssh.com encryption and *-etm@openssh.com MAC algorithms in the affected configuration, and use unaffected algorithms like AES-GCM instead.

    +

    Remediation

    +

    Upgrade golang.org/x/crypto/ssh to version 0.17.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Information Exposure

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gnutls28/libgnutls30 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + apt@2.4.11 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + openldap/libldap-2.5-0@2.5.17+dfsg-0ubuntu0.22.04.1 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + rtmpdump/librtmp1@2.4+20151223.gitfa8646d.1-2build4 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    A flaw was found in GnuTLS. The Minerva attack is a cryptographic vulnerability that exploits deterministic behavior in systems like GnuTLS, leading to side-channel leaks. In specific scenarios, such as when using the GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE flag, it can result in a noticeable step in nonce size from 513 to 512 bits, exposing a potential timing side-channel.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 gnutls28.

    +

    References

    + + +
    + + + +
    +
    +

    Uncaught Exception

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gnutls28/libgnutls30 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + apt@2.4.11 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + openldap/libldap-2.5-0@2.5.17+dfsg-0ubuntu0.22.04.1 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + rtmpdump/librtmp1@2.4+20151223.gitfa8646d.1-2build4 + + gnutls28/libgnutls30@3.7.3-4ubuntu1.4 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    A flaw has been discovered in GnuTLS where an application crash can be induced when attempting to verify a specially crafted .pem bundle using the "certtool --verify-chain" command.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 gnutls28.

    +

    References

    + + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/helm/v3 /usr/local/bin/helm +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + 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

    + +
    + + + +
    +
    +

    Improper Handling of Highly Compressed Data (Data Amplification)

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argo-cd/v2 /usr/local/bin/argocd +
    • +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/go-jose/go-jose/v3 +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and github.com/go-jose/go-jose/v3@v3.0.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + github.com/go-jose/go-jose/v3@v3.0.1 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Improper Handling of Highly Compressed Data (Data Amplification). An attacker could send a JWE containing compressed data that, when decompressed by Decrypt or DecryptMulti, would use large amounts of memory and CPU.

    +

    Remediation

    +

    Upgrade github.com/go-jose/go-jose/v3 to version 3.0.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + bash +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and bash@5.1-6ubuntu1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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. + 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

    +

    Upgrade Ubuntu:22.04 bash to version 5.1-6ubuntu1.1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-7008

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + systemd/libsystemd0 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and systemd/libsystemd0@249.11-0ubuntu3.12 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + apt@2.4.11 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + procps/libprocps8@2:3.3.17-6ubuntu2.1 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + util-linux@2.37.2-4ubuntu3 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + util-linux/bsdutils@1:2.37.2-4ubuntu3 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + systemd/libsystemd0@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + systemd/libudev1@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + libfido2/libfido2-1@1.10.0-1 + + systemd/libudev1@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + util-linux@2.37.2-4ubuntu3 + + systemd/libudev1@249.11-0ubuntu3.12 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + systemd/libudev1@249.11-0ubuntu3.12 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    A vulnerability was found in systemd-resolved. This issue may allow systemd-resolved to accept records of DNSSEC-signed domains even when they have no signature, allowing man-in-the-middles (or the upstream DNS resolver) to manipulate records.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 systemd.

    +

    References

    + + +
    + + + +
    +
    +

    Arbitrary Code Injection

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + shadow/passwd +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and shadow/passwd@1:4.8.1-2ubuntu2.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + shadow/login@1:4.8.1-2ubuntu2.2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream shadow package and not the shadow package as distributed by Ubuntu. + 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

    + + +
    + + + +
    +
    +

    Uncontrolled Recursion

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + pcre3/libpcre3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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. + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + patch +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and patch@2.7.6-7build2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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. + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + patch +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and patch@2.7.6-7build2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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. + 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-50495

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + ncurses/libtinfo6 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and ncurses/libtinfo6@6.3-2ubuntu0.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + bash@5.1-6ubuntu1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + less@590-1ubuntu0.22.04.2 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + libedit/libedit2@3.1-20210910-1build1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/ncurses-bin@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + util-linux@2.37.2-4ubuntu3 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + readline/libreadline8@8.1.2-1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + pinentry/pinentry-curses@1.1.1-1build2 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + pinentry/pinentry-curses@1.1.1-1build2 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/ncurses-base@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/ncurses-bin@6.3-2ubuntu0.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    NCurse v6.4-20230418 was discovered to contain a segmentation fault via the component _nc_wrap_entry().

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 ncurses.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-45918

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + ncurses/libtinfo6 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and ncurses/libtinfo6@6.3-2ubuntu0.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + bash@5.1-6ubuntu1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + less@590-1ubuntu0.22.04.2 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + libedit/libedit2@3.1-20210910-1build1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/ncurses-bin@6.3-2ubuntu0.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + util-linux@2.37.2-4ubuntu3 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + readline/libreadline8@8.1.2-1 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + pinentry/pinentry-curses@1.1.1-1build2 + + ncurses/libtinfo6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + pinentry/pinentry-curses@1.1.1-1build2 + + ncurses/libncursesw6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + procps@2:3.3.17-6ubuntu2.1 + + ncurses/libncurses6@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/ncurses-base@6.3-2ubuntu0.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + ncurses/ncurses-bin@6.3-2ubuntu0.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

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

    +

    ncurses 6.4-20230610 has a NULL pointer dereference in tgetstr in tinfo/lib_termcap.c.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 ncurses.

    +

    References

    + + +
    + + + +
    +
    +

    Resource Exhaustion

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + libzstd/libzstd1 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and libzstd/libzstd1@1.4.8+dfsg-3build1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and krb5/libk5crypto3@1.19.2-2ubuntu0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + openssh/openssh-client@1:8.9p1-3ubuntu0.6 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.15 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.2 + + pam/libpam-modules@1.4.0-11ubuntu2.4 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.3 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + krb5/libkrb5support0@1.19.2-2ubuntu0.3 + + + +
    • +
    + +
    + +
    + +

    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.

    +

    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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gnupg2/gpgv +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and gnupg2/gpgv@2.2.27-3ubuntu2.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gpgv@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + apt@2.4.11 + + gnupg2/gpgv@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpgv@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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.9 + + 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.9 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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.9 + + gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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.9 + + gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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.9 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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.9 + + 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.9 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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.9 + + 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.9 + + 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.9 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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.9 + + gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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.9 + + gnupg2/gpgsm@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpgsm@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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. + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + glibc/libc-bin +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and glibc/libc-bin@2.35-0ubuntu3.6 + +
    • +
    + +
    + + +

    Detailed paths

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

    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.

    +

    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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + git/git-man +
    • + +
    • Introduced through: + + + docker-image|quay.io/argoproj/argocd@v2.9.9, git@1:2.34.1-1ubuntu1.10 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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.9 + + git@1:2.34.1-1ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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. + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gcc-12/libstdc++6 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + apt@2.4.11 + + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + apt@2.4.11 + + apt/libapt-pkg6.0@2.4.11 + + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + gcc-12/gcc-12-base@12.3.0-1ubuntu1~22.04 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + 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. + 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 +
    + +
    + +
      +
    • + Manifest file: quay.io/argoproj/argocd:v2.9.9/argoproj/argocd Dockerfile +
    • +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + coreutils +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.9 and coreutils@8.32-4.1ubuntu1.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.9 + + coreutils@8.32-4.1ubuntu1.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream coreutils package and not the coreutils package as distributed by Ubuntu. + 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

    + + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.9.9/redis_7.0.11-alpine.html b/docs/snyk/v2.9.9/redis_7.0.11-alpine.html new file mode 100644 index 0000000000000..55538b9b23982 --- /dev/null +++ b/docs/snyk/v2.9.9/redis_7.0.11-alpine.html @@ -0,0 +1,2032 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    March 24th 2024, 12:18:14 am (UTC+00:00)

    +
    +
    + Scanned the following path: +
      +
    • redis:7.0.11-alpine (apk)
    • +
    +
    + +
    +
    9 known vulnerabilities
    +
    77 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

    + + +
    + + + +
    +
    +

    CVE-2023-5363

    +
    + +
    + high 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

    + + +
    + + + +
    +
    +

    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. + 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

    + + +
    + + + +
    +
    +

    Improper Check for Unusual or Exceptional Conditions

    +
    + +
    + 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: Generating excessively long X9.42 DH keys or checking + excessively long X9.42 DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_generate_key() to + generate an X9.42 DH key may experience long delays. Likewise, applications + that use DH_check_pub_key(), DH_check_pub_key_ex() or EVP_PKEY_public_check() + to check an X9.42 DH key or X9.42 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.

    +

    While DH_check() performs all the necessary checks (as of CVE-2023-3817), + DH_check_pub_key() doesn't make any of these checks, and is therefore + vulnerable for excessively large P and Q parameters.

    +

    Likewise, while DH_generate_key() performs a check for an excessively large + P, it doesn't check for an excessively large Q.

    +

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

    +

    DH_generate_key() and DH_check_pub_key() are also 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_pub_key_ex(), EVP_PKEY_public_check(), and EVP_PKEY_generate().

    +

    Also vulnerable are the OpenSSL pkey command line application when using the + "-pubcheck" option, as well as the OpenSSL genpkey command line application.

    +

    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.4-r1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + 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: The POLY1305 MAC (message authentication code) implementation + contains a bug that might corrupt the internal state of applications running + on PowerPC CPU based platforms if the CPU provides vector instructions.

    +

    Impact summary: If an attacker can influence whether the POLY1305 MAC + algorithm is used, the application state might be corrupted with various + application dependent consequences.

    +

    The POLY1305 MAC (message authentication code) implementation in OpenSSL for + PowerPC CPUs restores the contents of vector registers in a different order + than they are saved. Thus the contents of some of these vector registers + are corrupted when returning to the caller. The vulnerable code is used only + on newer PowerPC processors supporting the PowerISA 2.07 instructions.

    +

    The consequences of this kind of internal application state corruption can + be various - from no consequences, if the calling application does not + depend on the contents of non-volatile XMM registers at all, to the worst + consequences, where the attacker could get complete control of the application + process. However unless the compiler uses the vector registers for storing + pointers, the most likely consequence, if any, would be an incorrect result + of some application dependent calculations or a crash leading to a denial of + service.

    +

    The POLY1305 MAC algorithm is most frequently used as part of the + CHACHA20-POLY1305 AEAD (authenticated encryption with associated data) + algorithm. The most common usage of this AEAD cipher is with TLS protocol + versions 1.2 and 1.3. If this cipher is enabled on the server a malicious + client can influence whether this AEAD cipher is used. This implies that + TLS server applications using OpenSSL can be potentially impacted. However + we are currently not aware of any concrete application that would be affected + by this issue therefore we consider this a Low severity security issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2024-0727

    +
    + +
    + 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: Processing a maliciously formatted PKCS12 file may lead OpenSSL + to crash leading to a potential Denial of Service attack

    +

    Impact summary: Applications loading files in the PKCS12 format from untrusted + sources might terminate abruptly.

    +

    A file in PKCS12 format can contain certificates and keys and may come from an + untrusted source. The PKCS12 specification allows certain fields to be NULL, but + OpenSSL does not correctly check for this case. This can lead to a NULL pointer + dereference that results in OpenSSL crashing. If an application processes PKCS12 + files from an untrusted source using the OpenSSL APIs then that application will + be vulnerable to this issue.

    +

    OpenSSL APIs that are vulnerable to this are: PKCS12_parse(), + PKCS12_unpack_p7data(), PKCS12_unpack_p7encdata(), PKCS12_unpack_authsafes() + and PKCS12_newpass().

    +

    We have also fixed a similar issue in SMIME_write_PKCS7(). However since this + function is related to writing data we do not consider it security significant.

    +

    The FIPS modules in 3.2, 3.1 and 3.0 are not affected by this issue.

    +

    Remediation

    +

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

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-6237

    +
    + +
    + 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

    +

    This vulnerability has not been analyzed by NVD yet.

    +

    Remediation

    +

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

    + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/understand_the_basics.md b/docs/understand_the_basics.md index 15918c74a5dc1..0fd7218d5890b 100644 --- a/docs/understand_the_basics.md +++ b/docs/understand_the_basics.md @@ -11,5 +11,6 @@ Before effectively using Argo CD, it is necessary to understand the underlying t * Depending on how you plan to template your applications: * [Kustomize](https://kustomize.io) * [Helm](https://helm.sh) -* If you're integrating with Jenkins: - * [Jenkins User Guide](https://jenkins.io) +* If you're integrating with a CI tool: + * [GitHub Actions Documentation](https://docs.github.com/en/actions) + * [Jenkins User Guide](https://www.jenkins.io/doc/book/) diff --git a/docs/user-guide/annotations-and-labels.md b/docs/user-guide/annotations-and-labels.md new file mode 100644 index 0000000000000..032824c8708f3 --- /dev/null +++ b/docs/user-guide/annotations-and-labels.md @@ -0,0 +1,26 @@ +# Annotations and Labels used by Argo CD + +## Annotations + +| Annotation key | Target resource(es) | Possible values | Description | +|--------------------------------------------|---------------------|---------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| argocd.argoproj.io/application-set-refresh | ApplicationSet | `"true"` | Added when an ApplicationSet is requested to be refreshed by a webhook. The ApplicationSet controller will remove this annotation at the end of reconciliation. | +| argocd.argoproj.io/compare-options | any | [see compare options docs](compare-options.md) | Configures how an app's current state is compared to its desired state. | +| argocd.argoproj.io/hook | any | [see resource hooks docs](resource_hooks.md) | Used to configure [resource hooks](resource_hooks.md). | +| argocd.argoproj.io/hook-delete-policy | any | [see resource hooks docs](resource_hooks.md#hook-deletion-policies) | Used to set a [resource hook's deletion policy](resource_hooks.md#hook-deletion-policies). | +| argocd.argoproj.io/manifest-generate-paths | Application | [see scaling docs](../operator-manual/high_availability.md#webhook-and-manifest-paths-annotation) | Used to avoid unnecessary Application refreshes, especially in mono-repos. | +| argocd.argoproj.io/refresh | Application | `normal`, `hard` | Indicates that app needs to be refreshed. Removed by application controller after app is refreshed. Value `"hard"` means manifest cache and target cluster state cache should be invalidated before refresh. | +| argocd.argoproj.io/skip-reconcile | Application | `"true"` | Indicates to the Argo CD application controller that the Application should not be reconciled. See the [skip reconcile documentation](skip_reconcile.md) for use cases. | +| argocd.argoproj.io/sync-options | any | [see sync options docs](sync-options.md) | Provides a variety of settings to determine how an Application's resources are synced. | +| argocd.argoproj.io/sync-wave | any | [see sync waves docs](sync-waves.md) | | +| argocd.argoproj.io/tracking-id | any | any | Used by Argo CD to track resources it manages. See [resource tracking docs](resource_tracking.md) for details. | +| link.argocd.argoproj.io/{some link name} | any | An http(s) URL | Adds a link to the Argo CD UI for the resource. See [external URL docs](external-url.md) for details. | +| pref.argocd.argoproj.io/default-pod-sort | Application | [see UI customization docs](../operator-manual/ui-customization.md) | Sets the Application's default grouping mechanism. | +| pref.argocd.argoproj.io/default-view | Application | [see UI customization docs](../operator-manual/ui-customization.md) | Sets the Application's default view mode (e.g. "tree" or "list") | + +## 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. | diff --git a/docs/user-guide/app_deletion.md b/docs/user-guide/app_deletion.md index 6f7ca8d9caf06..a1eaedf41cd04 100644 --- a/docs/user-guide/app_deletion.md +++ b/docs/user-guide/app_deletion.md @@ -22,11 +22,12 @@ or argocd app delete APPNAME ``` -# Deletion Using `kubectl` +## Deletion Using `kubectl` -To perform a non-cascade delete: +To perform a non-cascade delete, make sure the finalizer is unset and then delete the app: ```bash +kubectl patch app APPNAME -p '{"metadata": {"finalizers": null}}' --type merge kubectl delete app APPNAME ``` @@ -37,16 +38,23 @@ kubectl patch app APPNAME -p '{"metadata": {"finalizers": ["resources-finalizer kubectl delete app APPNAME ``` -# About The Deletion Finalizer +## About The Deletion Finalizer ```yaml metadata: finalizers: + # The default behaviour is foreground cascading deletion - resources-finalizer.argocd.argoproj.io + # Alternatively, you can use background cascading deletion + # - resources-finalizer.argocd.argoproj.io/background ``` When deleting an Application with this finalizer, the Argo CD application controller will perform a cascading delete of the Application's resources. Adding the finalizer enables cascading deletes when implementing [the App of Apps pattern](../operator-manual/cluster-bootstrapping.md#cascading-deletion). +The default propagation policy for cascading deletion is [foreground cascading deletion](https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion). +Argo CD performs [background cascading deletion](https://kubernetes.io/docs/concepts/architecture/garbage-collection/#background-deletion) when `resources-finalizer.argocd.argoproj.io/background` is set. + When you invoke `argocd app delete` with `--cascade`, the finalizer is added automatically. +You can set the propagation policy with `--propagation-policy `. diff --git a/docs/user-guide/application-set.md b/docs/user-guide/application-set.md index 58a3f58ed4470..c8a05d4cb4bdd 100644 --- a/docs/user-guide/application-set.md +++ b/docs/user-guide/application-set.md @@ -1,6 +1,6 @@ ### Automating the generation of Argo CD Applications with the ApplicationSet Controller -The [ApplicationSet controller](../operator-manual/applicationset/index.md) is a part of Argo CD adds Application automation, and seeks to improve multi-cluster support and cluster multitenant support within Argo CD. Argo CD Applications may be templated from multiple different sources, including from Git or Argo CD's own defined cluster list. +The [ApplicationSet controller](../operator-manual/applicationset/index.md) adds Application automation and seeks to improve multi-cluster support and cluster multitenant support within Argo CD. Argo CD Applications may be templated from multiple different sources, including from Git or Argo CD's own defined cluster list. The set of tools provided by the ApplicationSet controller may also be used to allow developers (without access to the Argo CD namespace) to independently create Applications without cluster-administrator intervention. @@ -8,7 +8,7 @@ The set of tools provided by the ApplicationSet controller may also be used to a Be aware of the [security implications](../operator-manual/applicationset/Security.md) before allowing developers to create Applications via ApplicationSets. -The ApplicationSet controller is installed alongside Argo CD (within the same namespace), and the controller automatically generates Argo CD Applications based on the contents of a new `ApplicationSet` Custom Resource (CR). +The ApplicationSet controller automatically generates Argo CD Applications based on the contents of an `ApplicationSet` Custom Resource (CR). Here is an example of an `ApplicationSet` resource that can be used to target an Argo CD Application to multiple clusters: ```yaml @@ -17,6 +17,8 @@ kind: ApplicationSet metadata: name: guestbook spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - list: elements: @@ -28,15 +30,15 @@ spec: url: https://9.8.7.6 template: metadata: - name: '{{cluster}}-guestbook' + name: '{{.cluster}}-guestbook' spec: - project: default + project: my-project source: - repoURL: https://github.com/argoproj/argo-cd.git + repoURL: https://github.com/infra-team/cluster-deployments.git targetRevision: HEAD - path: applicationset/examples/list-generator/guestbook/{{cluster}} + path: guestbook/{{.cluster}} destination: - server: '{{url}}' + server: '{{.url}}' namespace: guestbook ``` @@ -46,42 +48,4 @@ Likewise, changes made to the ApplicationSet `template` fields will automaticall Within ApplicationSet there exist other more powerful generators in addition to the List generator, including the Cluster generator (which automatically uses Argo CD-defined clusters to template Applications), and the Git generator (which uses the files/directories of a Git repository to template applications). -To learn more about the ApplicationSet controller, check out [ApplicationSet documentation](../operator-manual/applicationset/index.md) to install the ApplicationSet controller alongside Argo CD. - -**Note:** Starting `v2.3` of Argo CD, we don't need to install ApplicationSet Controller separately. It would be instead as part of Argo CD installation. - -#### 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`: - -```yaml -apiVersion: argoproj.io/v1alpha1 -kind: ApplicationSet -metadata: - name: guestbook -spec: - generators: - - list: - elements: - - cluster: engineering-dev - url: https://kubernetes.default.svc - env: staging - - cluster: engineering-prod - url: https://kubernetes.default.svc - env: prod - selector: - matchLabels: - env: staging - template: - metadata: - name: '{{cluster}}-guestbook' - spec: - project: default - source: - repoURL: https://github.com/argoproj-labs/applicationset.git - targetRevision: HEAD - path: examples/list-generator/guestbook/{{cluster}} - destination: - server: '{{url}}' - namespace: guestbook -``` \ No newline at end of file +To learn more about the ApplicationSet controller, check out the [ApplicationSet documentation](../operator-manual/applicationset/index.md). diff --git a/docs/user-guide/application-specification.md b/docs/user-guide/application-specification.md new file mode 100644 index 0000000000000..4f581b19a47fa --- /dev/null +++ b/docs/user-guide/application-specification.md @@ -0,0 +1,7 @@ +# Application Specification + +The following describes all the available fields of an Application: + +```yaml +{!docs/operator-manual/application.yaml!} +``` diff --git a/docs/user-guide/best_practices.md b/docs/user-guide/best_practices.md index 61a2005b590f0..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 @@ -63,7 +63,7 @@ repository or kustomize base. For example, consider the following kustomization.yaml ```yaml -bases: +resources: - github.com/argoproj/argo-cd//manifests/cluster-install ``` diff --git a/docs/user-guide/build-environment.md b/docs/user-guide/build-environment.md index 56f6e6b436463..8e2448f4f9e7f 100644 --- a/docs/user-guide/build-environment.md +++ b/docs/user-guide/build-environment.md @@ -3,10 +3,11 @@ [Custom tools](../operator-manual/config-management-plugins.md), [Helm](helm.md), [Jsonnet](jsonnet.md), and [Kustomize](kustomize.md) support the following build env vars: | Variable | Description | -| ----------------------------------- | ----------------------------------------------------------------------- | +|-------------------------------------|-------------------------------------------------------------------------| | `ARGOCD_APP_NAME` | The name of the application. | | `ARGOCD_APP_NAMESPACE` | The destination namespace of the application. | | `ARGOCD_APP_REVISION` | The resolved revision, e.g. `f913b6cbf58aa5ae5ca1f8a2b149477aebcbd9d8`. | +| `ARGOCD_APP_REVISION_SHORT` | The resolved short revision, e.g. `f913b6c`. | | `ARGOCD_APP_SOURCE_PATH` | The path of the app within the source repo. | | `ARGOCD_APP_SOURCE_REPO_URL` | The source repo URL. | | `ARGOCD_APP_SOURCE_TARGET_REVISION` | The target revision from the spec, e.g. `master`. | 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.md b/docs/user-guide/commands/argocd.md index 86cc01d9443fa..b03b3971284f6 100644 --- a/docs/user-guide/commands/argocd.md +++ b/docs/user-guide/commands/argocd.md @@ -1,3 +1,5 @@ +# `argocd` Command Reference + ## argocd argocd controls a Argo CD server @@ -13,6 +15,7 @@ argocd [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -26,8 +29,12 @@ argocd [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_account.md b/docs/user-guide/commands/argocd_account.md index 3880bdb6fffc4..88d483ffac68e 100644 --- a/docs/user-guide/commands/argocd_account.md +++ b/docs/user-guide/commands/argocd_account.md @@ -1,3 +1,5 @@ +# `argocd account` Command Reference + ## argocd account Manage account settings @@ -6,6 +8,22 @@ Manage account settings argocd account [flags] ``` +### Examples + +``` + # List accounts + argocd account list + + # Update the current user's password + argocd account update-password + + # Can I sync any app? + argocd account can-i sync applications '*' + + # Get User information + argocd account get-user-info +``` + ### Options ``` @@ -17,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 @@ -37,6 +56,7 @@ argocd account [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -49,14 +69,18 @@ argocd account [flags] --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 + --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") ``` ### SEE ALSO * [argocd](argocd.md) - argocd controls a Argo CD server -* [argocd account bcrypt](argocd_account_bcrypt.md) - Generate bcrypt hash for the admin password +* [argocd account bcrypt](argocd_account_bcrypt.md) - Generate bcrypt hash for any password * [argocd account can-i](argocd_account_can-i.md) - Can I * [argocd account delete-token](argocd_account_delete-token.md) - Deletes account token * [argocd account generate-token](argocd_account_generate-token.md) - Generate account token diff --git a/docs/user-guide/commands/argocd_account_bcrypt.md b/docs/user-guide/commands/argocd_account_bcrypt.md index 0e7d1a13a1735..6bc282cfaab1e 100644 --- a/docs/user-guide/commands/argocd_account_bcrypt.md +++ b/docs/user-guide/commands/argocd_account_bcrypt.md @@ -1,11 +1,20 @@ +# `argocd account bcrypt` Command Reference + ## argocd account bcrypt -Generate bcrypt hash for the admin password +Generate bcrypt hash for any password ``` argocd account bcrypt [flags] ``` +### Examples + +``` +# Generate bcrypt hash for any password +argocd account bcrypt --password YOUR_PASSWORD +``` + ### Options ``` @@ -20,6 +29,7 @@ argocd account bcrypt [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +42,12 @@ argocd account bcrypt [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_account_can-i.md b/docs/user-guide/commands/argocd_account_can-i.md index 799d3be70da51..6e6cb2bea524b 100644 --- a/docs/user-guide/commands/argocd_account_can-i.md +++ b/docs/user-guide/commands/argocd_account_can-i.md @@ -1,3 +1,5 @@ +# `argocd account can-i` Command Reference + ## argocd account can-i Can I @@ -37,6 +39,7 @@ Resources: [clusters projects applications applicationsets repositories certific --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -49,8 +52,12 @@ Resources: [clusters projects applications applicationsets repositories certific --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_account_delete-token.md b/docs/user-guide/commands/argocd_account_delete-token.md index 1223b91c037e5..6ef4cf11499fe 100644 --- a/docs/user-guide/commands/argocd_account_delete-token.md +++ b/docs/user-guide/commands/argocd_account_delete-token.md @@ -1,3 +1,5 @@ +# `argocd account delete-token` Command Reference + ## argocd account delete-token Deletes account token @@ -30,6 +32,7 @@ argocd account delete-token --account ID --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -42,8 +45,12 @@ argocd account delete-token --account ID --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_account_generate-token.md b/docs/user-guide/commands/argocd_account_generate-token.md index 34ecdc7704c33..0d21d36ad32ff 100644 --- a/docs/user-guide/commands/argocd_account_generate-token.md +++ b/docs/user-guide/commands/argocd_account_generate-token.md @@ -1,3 +1,5 @@ +# `argocd account generate-token` Command Reference + ## argocd account generate-token Generate account token @@ -32,6 +34,7 @@ argocd account generate-token --account --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -44,8 +47,12 @@ argocd account generate-token --account --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_account_get-user-info.md b/docs/user-guide/commands/argocd_account_get-user-info.md index 9f15863916cdd..66603a52b2628 100644 --- a/docs/user-guide/commands/argocd_account_get-user-info.md +++ b/docs/user-guide/commands/argocd_account_get-user-info.md @@ -1,3 +1,5 @@ +# `argocd account get-user-info` Command Reference + ## argocd account get-user-info Get user info @@ -6,6 +8,16 @@ Get user info argocd account get-user-info [flags] ``` +### Examples + +``` + # Get User information for the currently logged-in user (see 'argocd login') + argocd account get-user-info + + # Get User information in yaml format + argocd account get-user-info -o yaml +``` + ### Options ``` @@ -20,6 +32,7 @@ argocd account get-user-info [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +45,12 @@ argocd account get-user-info [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_account_get.md b/docs/user-guide/commands/argocd_account_get.md index f1149ad1c80fc..fbe0ef6027141 100644 --- a/docs/user-guide/commands/argocd_account_get.md +++ b/docs/user-guide/commands/argocd_account_get.md @@ -1,3 +1,5 @@ +# `argocd account get` Command Reference + ## argocd account get Get account details @@ -31,6 +33,7 @@ argocd account get --account --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -43,8 +46,12 @@ argocd account get --account --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_account_list.md b/docs/user-guide/commands/argocd_account_list.md index 0604b6fb535db..0082c0260496c 100644 --- a/docs/user-guide/commands/argocd_account_list.md +++ b/docs/user-guide/commands/argocd_account_list.md @@ -1,3 +1,5 @@ +# `argocd account list` Command Reference + ## argocd account list List accounts @@ -26,6 +28,7 @@ argocd account list --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -38,8 +41,12 @@ argocd account list --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_account_update-password.md b/docs/user-guide/commands/argocd_account_update-password.md index e386e7b69f20a..ed84a7da00617 100644 --- a/docs/user-guide/commands/argocd_account_update-password.md +++ b/docs/user-guide/commands/argocd_account_update-password.md @@ -1,3 +1,5 @@ +# `argocd account update-password` Command Reference + ## argocd account update-password Update an account's password @@ -29,10 +31,10 @@ argocd account update-password [flags] ### Options ``` - --account string an account name that should be updated. Defaults to current user account - --current-password string password of the currently logged on user + --account string An account name that should be updated. Defaults to current user account + --current-password string Password of the currently logged on user -h, --help help for update-password - --new-password string new password you want to update to + --new-password string New password you want to update to ``` ### Options inherited from parent commands @@ -42,6 +44,7 @@ argocd account update-password [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -54,8 +57,12 @@ argocd account update-password [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin.md b/docs/user-guide/commands/argocd_admin.md index aff92561bdf7f..7966e5a3cb9b1 100644 --- a/docs/user-guide/commands/argocd_admin.md +++ b/docs/user-guide/commands/argocd_admin.md @@ -1,3 +1,5 @@ +# `argocd admin` Command Reference + ## argocd admin Contains a set of commands useful for Argo CD administrators and requires direct Kubernetes access @@ -6,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 ``` @@ -21,6 +109,7 @@ argocd admin [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +120,12 @@ argocd admin [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_app.md b/docs/user-guide/commands/argocd_admin_app.md index 70a548c0e9947..58e0f50f25846 100644 --- a/docs/user-guide/commands/argocd_admin_app.md +++ b/docs/user-guide/commands/argocd_admin_app.md @@ -1,3 +1,5 @@ +# `argocd admin app` Command Reference + ## argocd admin app Manage applications configuration @@ -6,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 ``` @@ -19,6 +36,7 @@ argocd admin app [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +49,12 @@ argocd admin app [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_app_diff-reconcile-results.md b/docs/user-guide/commands/argocd_admin_app_diff-reconcile-results.md index 02ddbee5ac8cb..39190e23349fc 100644 --- a/docs/user-guide/commands/argocd_admin_app_diff-reconcile-results.md +++ b/docs/user-guide/commands/argocd_admin_app_diff-reconcile-results.md @@ -1,3 +1,5 @@ +# `argocd admin app diff-reconcile-results` Command Reference + ## argocd admin app diff-reconcile-results Compare results of two reconciliations and print diff. @@ -19,6 +21,7 @@ argocd admin app diff-reconcile-results PATH1 PATH2 [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +34,12 @@ argocd admin app diff-reconcile-results PATH1 PATH2 [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_app_generate-spec.md b/docs/user-guide/commands/argocd_admin_app_generate-spec.md index fc5ff079954ad..ed9f36a4268c0 100644 --- a/docs/user-guide/commands/argocd_admin_app_generate-spec.md +++ b/docs/user-guide/commands/argocd_admin_app_generate-spec.md @@ -1,3 +1,5 @@ +# `argocd admin app generate-spec` Command Reference + ## argocd admin app generate-spec Generate declarative config for an application @@ -65,6 +67,9 @@ argocd admin app generate-spec APPNAME [flags] --kustomize-force-common-annotation Force common annotations in Kustomize --kustomize-force-common-label Force common labels in Kustomize --kustomize-image stringArray Kustomize images (e.g. --kustomize-image node:8.15.0 --kustomize-image mysql=mariadb,alpine@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d) + --kustomize-label-without-selector Do not apply common label to selectors or templates + --kustomize-namespace string Kustomize namespace + --kustomize-replica stringArray Kustomize replicas (e.g. --kustomize-replica my-development=2 --kustomize-replica my-statefulset=4) --kustomize-version string Kustomize version -l, --label stringArray Labels to apply to the app --name string A name for the app, ignored if a file is set (DEPRECATED) @@ -75,13 +80,14 @@ argocd admin app generate-spec APPNAME [flags] --path string Path in repository to the app directory, ignored if a file is set --plugin-env stringArray Additional plugin envs --project string Application project name + --ref string Ref is reference to another source within sources field --release-name string Helm release-name --repo string Repository URL, ignored if a file is set --revision string The tracking source branch, tag, commit or Helm chart version the application will sync to --revision-history-limit int How many items to keep in revision history (default 10) --self-heal Set self healing when sync is automated --sync-option Prune=false Add or remove a sync option, e.g add Prune=false. Remove using `!` prefix, e.g. `!Prune=false` - --sync-policy string Set the sync policy (one of: none, automated (aliases of automated: auto, automatic)) + --sync-policy string Set the sync policy (one of: manual (aliases of manual: none), automated (aliases of automated: auto, automatic)) --sync-retry-backoff-duration duration Sync retry backoff base duration. Input needs to be a duration (e.g. 2m, 1h) (default 5s) --sync-retry-backoff-factor int Factor multiplies the base duration after each failed sync retry (default 2) --sync-retry-backoff-max-duration duration Max sync retry backoff duration. Input needs to be a duration (e.g. 2m, 1h) (default 3m0s) @@ -98,6 +104,7 @@ argocd admin app generate-spec APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -110,8 +117,12 @@ argocd admin app generate-spec APPNAME [flags] --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 + --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") ``` ### SEE ALSO 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 37aacbdfc65df..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 @@ -1,3 +1,5 @@ +# `argocd admin app get-reconcile-results` Command Reference + ## argocd admin app get-reconcile-results Reconcile all applications and stores reconciliation summary in the specified file. @@ -17,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 @@ -29,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 @@ -42,6 +46,7 @@ argocd admin app get-reconcile-results PATH [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -54,7 +59,11 @@ argocd admin app get-reconcile-results PATH [flags] --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 + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_cluster.md b/docs/user-guide/commands/argocd_admin_cluster.md index 3ad9abadcbf9b..544c0de08959c 100644 --- a/docs/user-guide/commands/argocd_admin_cluster.md +++ b/docs/user-guide/commands/argocd_admin_cluster.md @@ -1,3 +1,5 @@ +# `argocd admin cluster` Command Reference + ## argocd admin cluster Manage clusters configuration @@ -6,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 ``` @@ -19,6 +35,7 @@ argocd admin cluster [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +48,12 @@ argocd admin cluster [flags] --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 + --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") ``` ### SEE ALSO @@ -41,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 8dc901a088dc1..79f88233fab32 100644 --- a/docs/user-guide/commands/argocd_admin_cluster_generate-spec.md +++ b/docs/user-guide/commands/argocd_admin_cluster_generate-spec.md @@ -1,3 +1,5 @@ +# `argocd admin cluster generate-spec` Command Reference + ## argocd admin cluster generate-spec Generate declarative config for a cluster @@ -11,8 +13,10 @@ 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'. --cluster-resources Indicates if cluster level resources should be managed. The setting is used only if list of managed namespaces is not empty. --exec-command string Command to run to provide client credentials to the cluster. You may need to build a custom ArgoCD image to ensure the command is available at runtime. --exec-command-api-version string Preferred input version of the ExecInfo for the --exec-command executable @@ -40,6 +44,7 @@ argocd admin cluster generate-spec CONTEXT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -52,8 +57,12 @@ argocd admin cluster generate-spec CONTEXT [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_cluster_kubeconfig.md b/docs/user-guide/commands/argocd_admin_cluster_kubeconfig.md index f1a8455af3256..38f61ce5cd8a2 100644 --- a/docs/user-guide/commands/argocd_admin_cluster_kubeconfig.md +++ b/docs/user-guide/commands/argocd_admin_cluster_kubeconfig.md @@ -1,3 +1,5 @@ +# `argocd admin cluster kubeconfig` Command Reference + ## argocd admin cluster kubeconfig Generates kubeconfig for the specified cluster @@ -6,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 ``` @@ -17,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 @@ -38,6 +58,7 @@ argocd admin cluster kubeconfig CLUSTER_URL OUTPUT_PATH [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -50,7 +71,11 @@ argocd admin cluster kubeconfig CLUSTER_URL OUTPUT_PATH [flags] --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 + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_cluster_namespaces.md b/docs/user-guide/commands/argocd_admin_cluster_namespaces.md index f302f14ff8a90..fee5c7679e159 100644 --- a/docs/user-guide/commands/argocd_admin_cluster_namespaces.md +++ b/docs/user-guide/commands/argocd_admin_cluster_namespaces.md @@ -1,3 +1,5 @@ +# `argocd admin cluster namespaces` Command Reference + ## argocd admin cluster namespaces Print information namespaces which Argo CD manages in each cluster. @@ -17,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 @@ -38,6 +41,7 @@ argocd admin cluster namespaces [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -50,7 +54,11 @@ argocd admin cluster namespaces [flags] --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 + --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-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") ``` ### SEE ALSO 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 17b66a06d65a0..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 @@ -1,3 +1,5 @@ +# `argocd admin cluster namespaces disable-namespaced-mode` Command Reference + ## argocd admin cluster namespaces disable-namespaced-mode Disable namespaced mode for clusters which name matches to the specified pattern. @@ -17,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 @@ -39,6 +42,7 @@ argocd admin cluster namespaces disable-namespaced-mode PATTERN [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -51,7 +55,11 @@ argocd admin cluster namespaces disable-namespaced-mode PATTERN [flags] --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 + --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-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") ``` ### SEE ALSO 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 b4a3f63c0d821..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 @@ -1,3 +1,5 @@ +# `argocd admin cluster namespaces enable-namespaced-mode` Command Reference + ## argocd admin cluster namespaces enable-namespaced-mode Enable namespaced mode for clusters which name matches to the specified pattern. @@ -18,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 @@ -41,6 +44,7 @@ argocd admin cluster namespaces enable-namespaced-mode PATTERN [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -53,7 +57,11 @@ argocd admin cluster namespaces enable-namespaced-mode PATTERN [flags] --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 + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_cluster_shards.md b/docs/user-guide/commands/argocd_admin_cluster_shards.md index be7cc36ccd662..48f6138d47b4a 100644 --- a/docs/user-guide/commands/argocd_admin_cluster_shards.md +++ b/docs/user-guide/commands/argocd_admin_cluster_shards.md @@ -1,6 +1,8 @@ +# `argocd admin cluster shards` Command Reference + ## 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] @@ -19,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 @@ -30,7 +33,7 @@ argocd admin cluster shards [flags] --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: none, gzip) (default "none") + --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. @@ -40,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 @@ -53,6 +57,7 @@ argocd admin cluster shards [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -65,7 +70,11 @@ argocd admin cluster shards [flags] --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 + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_cluster_stats.md b/docs/user-guide/commands/argocd_admin_cluster_stats.md index 586069e08e688..c5297ce7e35ed 100644 --- a/docs/user-guide/commands/argocd_admin_cluster_stats.md +++ b/docs/user-guide/commands/argocd_admin_cluster_stats.md @@ -1,3 +1,5 @@ +# `argocd admin cluster stats` Command Reference + ## argocd admin cluster stats Prints information cluster statistics and inferred shard number @@ -6,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 ``` @@ -19,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 @@ -30,7 +47,7 @@ argocd admin cluster stats [flags] --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: none, gzip) (default "none") + --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. @@ -40,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 @@ -53,6 +71,7 @@ argocd admin cluster stats [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -65,7 +84,11 @@ argocd admin cluster stats [flags] --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 + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_dashboard.md b/docs/user-guide/commands/argocd_admin_dashboard.md index 323497ebfc558..71e11a173906a 100644 --- a/docs/user-guide/commands/argocd_admin_dashboard.md +++ b/docs/user-guide/commands/argocd_admin_dashboard.md @@ -1,3 +1,5 @@ +# `argocd admin dashboard` Command Reference + ## argocd admin dashboard Starts Argo CD Web UI locally @@ -6,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 ``` @@ -18,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 @@ -25,7 +42,9 @@ argocd admin dashboard [flags] --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-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 @@ -39,6 +58,7 @@ argocd admin dashboard [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -51,8 +71,11 @@ argocd admin dashboard [flags] --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 - --server string Argo CD server address + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_export.md b/docs/user-guide/commands/argocd_admin_export.md index 27ff5ad1f9369..d168fe5450a74 100644 --- a/docs/user-guide/commands/argocd_admin_export.md +++ b/docs/user-guide/commands/argocd_admin_export.md @@ -1,3 +1,5 @@ +# `argocd admin export` Command Reference + ## argocd admin export Export all Argo CD data to stdout (default) or a file @@ -17,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 @@ -39,6 +42,7 @@ argocd admin export [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -51,7 +55,11 @@ argocd admin export [flags] --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 + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_import.md b/docs/user-guide/commands/argocd_admin_import.md index 62c9c9443e2e6..dc8a4b2dbf947 100644 --- a/docs/user-guide/commands/argocd_admin_import.md +++ b/docs/user-guide/commands/argocd_admin_import.md @@ -1,3 +1,5 @@ +# `argocd admin import` Command Reference + ## argocd admin import Import Argo CD data from stdin (specify `-') or a file @@ -17,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 @@ -42,6 +45,7 @@ argocd admin import SOURCE [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -54,7 +58,11 @@ argocd admin import SOURCE [flags] --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 + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_initial-password.md b/docs/user-guide/commands/argocd_admin_initial-password.md index 2f997d25d46d1..dbc44561debdc 100644 --- a/docs/user-guide/commands/argocd_admin_initial-password.md +++ b/docs/user-guide/commands/argocd_admin_initial-password.md @@ -1,3 +1,5 @@ +# `argocd admin initial-password` Command Reference + ## argocd admin initial-password Prints initial password to log in to Argo CD for the first time @@ -17,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 @@ -38,6 +41,7 @@ argocd admin initial-password [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -50,7 +54,11 @@ argocd admin initial-password [flags] --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 + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_notifications.md b/docs/user-guide/commands/argocd_admin_notifications.md index f2bb15b50d306..87429217f99e9 100644 --- a/docs/user-guide/commands/argocd_admin_notifications.md +++ b/docs/user-guide/commands/argocd_admin_notifications.md @@ -1,3 +1,5 @@ +# `argocd admin notifications` Command Reference + ## argocd admin notifications Set of CLI commands that helps manage notifications settings @@ -21,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 @@ -43,6 +46,7 @@ argocd admin notifications [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -55,7 +59,11 @@ argocd admin notifications [flags] --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 + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_notifications_template.md b/docs/user-guide/commands/argocd_admin_notifications_template.md index 472651a267cf7..75d5700aaac04 100644 --- a/docs/user-guide/commands/argocd_admin_notifications_template.md +++ b/docs/user-guide/commands/argocd_admin_notifications_template.md @@ -1,3 +1,5 @@ +# `argocd admin notifications template` Command Reference + ## argocd admin notifications template Notification templates related commands @@ -31,7 +33,9 @@ argocd admin notifications template [flags] --config string Path to Argo CD config (default "/home/user/.config/argocd/config") --config-map string argocd-notifications-cm.yaml file 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) @@ -48,10 +52,14 @@ argocd admin notifications template [flags] --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") --secret string argocd-notifications-secret.yaml file path. Use empty secret if provided value is ':empty' --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 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 58993c1abc80f..214a8e5cd442b 100644 --- a/docs/user-guide/commands/argocd_admin_notifications_template_get.md +++ b/docs/user-guide/commands/argocd_admin_notifications_template_get.md @@ -1,3 +1,5 @@ +# `argocd admin notifications template get` Command Reference + ## argocd admin notifications template get Prints information about configured templates @@ -43,7 +45,9 @@ argocd admin notifications template get app-sync-succeeded -o=yaml --config string Path to Argo CD config (default "/home/user/.config/argocd/config") --config-map string argocd-notifications-cm.yaml file 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) @@ -60,10 +64,14 @@ argocd admin notifications template get app-sync-succeeded -o=yaml --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") --secret string argocd-notifications-secret.yaml file path. Use empty secret if provided value is ':empty' --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 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 c9098e594ab22..4f94a9d960476 100644 --- a/docs/user-guide/commands/argocd_admin_notifications_template_notify.md +++ b/docs/user-guide/commands/argocd_admin_notifications_template_notify.md @@ -1,3 +1,5 @@ +# `argocd admin notifications template notify` Command Reference + ## argocd admin notifications template notify Generates notification using the specified template and send it to specified recipients @@ -44,7 +46,9 @@ argocd admin notifications template notify app-sync-succeeded guestbook --config string Path to Argo CD config (default "/home/user/.config/argocd/config") --config-map string argocd-notifications-cm.yaml file 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) @@ -61,10 +65,14 @@ argocd admin notifications template notify app-sync-succeeded guestbook --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") --secret string argocd-notifications-secret.yaml file path. Use empty secret if provided value is ':empty' --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 diff --git a/docs/user-guide/commands/argocd_admin_notifications_trigger.md b/docs/user-guide/commands/argocd_admin_notifications_trigger.md index bc4f82c9393a3..d6ff9e53ab235 100644 --- a/docs/user-guide/commands/argocd_admin_notifications_trigger.md +++ b/docs/user-guide/commands/argocd_admin_notifications_trigger.md @@ -1,3 +1,5 @@ +# `argocd admin notifications trigger` Command Reference + ## argocd admin notifications trigger Notification triggers related commands @@ -31,7 +33,9 @@ argocd admin notifications trigger [flags] --config string Path to Argo CD config (default "/home/user/.config/argocd/config") --config-map string argocd-notifications-cm.yaml file 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) @@ -48,10 +52,14 @@ argocd admin notifications trigger [flags] --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") --secret string argocd-notifications-secret.yaml file path. Use empty secret if provided value is ':empty' --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 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 625d71bd5de1e..acd2ab5af9553 100644 --- a/docs/user-guide/commands/argocd_admin_notifications_trigger_get.md +++ b/docs/user-guide/commands/argocd_admin_notifications_trigger_get.md @@ -1,3 +1,5 @@ +# `argocd admin notifications trigger get` Command Reference + ## argocd admin notifications trigger get Prints information about configured triggers @@ -43,7 +45,9 @@ argocd admin notifications trigger get on-sync-failed -o=yaml --config string Path to Argo CD config (default "/home/user/.config/argocd/config") --config-map string argocd-notifications-cm.yaml file 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) @@ -60,10 +64,14 @@ argocd admin notifications trigger get on-sync-failed -o=yaml --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") --secret string argocd-notifications-secret.yaml file path. Use empty secret if provided value is ':empty' --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 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 92f60bdcb8d1e..f8bebb2937937 100644 --- a/docs/user-guide/commands/argocd_admin_notifications_trigger_run.md +++ b/docs/user-guide/commands/argocd_admin_notifications_trigger_run.md @@ -1,3 +1,5 @@ +# `argocd admin notifications trigger run` Command Reference + ## argocd admin notifications trigger run Evaluates specified trigger condition and prints the result @@ -43,7 +45,9 @@ argocd admin notifications trigger run on-sync-status-unknown ./sample-app.yaml --config string Path to Argo CD config (default "/home/user/.config/argocd/config") --config-map string argocd-notifications-cm.yaml file 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) @@ -60,10 +64,14 @@ argocd admin notifications trigger run on-sync-status-unknown ./sample-app.yaml --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") --secret string argocd-notifications-secret.yaml file path. Use empty secret if provided value is ':empty' --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 diff --git a/docs/user-guide/commands/argocd_admin_proj.md b/docs/user-guide/commands/argocd_admin_proj.md index c78f74159b865..b22a2513b7e4d 100644 --- a/docs/user-guide/commands/argocd_admin_proj.md +++ b/docs/user-guide/commands/argocd_admin_proj.md @@ -1,3 +1,5 @@ +# `argocd admin proj` Command Reference + ## argocd admin proj Manage projects configuration @@ -19,6 +21,7 @@ argocd admin proj [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +34,12 @@ argocd admin proj [flags] --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 + --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") ``` ### SEE ALSO 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 a16531a200ee4..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 @@ -1,3 +1,5 @@ +# `argocd admin proj generate-allow-list` Command Reference + ## argocd admin proj generate-allow-list Generates project allow list from the specified clusterRole file @@ -6,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 ``` @@ -17,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 @@ -39,6 +49,7 @@ argocd admin proj generate-allow-list CLUSTERROLE_PATH PROJ_NAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -51,7 +62,11 @@ argocd admin proj generate-allow-list CLUSTERROLE_PATH PROJ_NAME [flags] --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 + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_proj_generate-spec.md b/docs/user-guide/commands/argocd_admin_proj_generate-spec.md index 4227f17459c64..b4f544367813d 100644 --- a/docs/user-guide/commands/argocd_admin_proj_generate-spec.md +++ b/docs/user-guide/commands/argocd_admin_proj_generate-spec.md @@ -1,3 +1,5 @@ +# `argocd admin proj generate-spec` Command Reference + ## argocd admin proj generate-spec Generate declarative config for a project @@ -6,6 +8,19 @@ Generate declarative config for a project argocd admin proj generate-spec PROJECT [flags] ``` +### Examples + +``` + # Generate a YAML configuration for a project named "myproject" + argocd admin projects generate-spec myproject + + # Generate a JSON configuration for a project named "anotherproject" and specify an output file + argocd admin projects generate-spec anotherproject --output json --file config.json + + # Generate a YAML configuration for a project named "someproject" and write it back to the input file + argocd admin projects generate-spec someproject --inline +``` + ### Options ``` @@ -33,6 +48,7 @@ argocd admin proj generate-spec PROJECT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -45,8 +61,12 @@ argocd admin proj generate-spec PROJECT [flags] --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 + --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") ``` ### SEE ALSO 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 f26b4c511a39a..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 @@ -1,3 +1,5 @@ +# `argocd admin proj update-role-policy` Command Reference + ## argocd admin proj update-role-policy Implement bulk project role update. Useful to back-fill existing project policies or remove obsolete actions. @@ -28,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 @@ -54,6 +57,7 @@ argocd admin proj update-role-policy PROJECT_GLOB MODIFICATION ACTION [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -66,7 +70,11 @@ argocd admin proj update-role-policy PROJECT_GLOB MODIFICATION ACTION [flags] --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 + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_repo.md b/docs/user-guide/commands/argocd_admin_repo.md index ef8566aece9e8..411cf558bac5b 100644 --- a/docs/user-guide/commands/argocd_admin_repo.md +++ b/docs/user-guide/commands/argocd_admin_repo.md @@ -1,3 +1,5 @@ +# `argocd admin repo` Command Reference + ## argocd admin repo Manage repositories configuration @@ -19,6 +21,7 @@ argocd admin repo [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +34,12 @@ argocd admin repo [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_repo_generate-spec.md b/docs/user-guide/commands/argocd_admin_repo_generate-spec.md index bf69b4016efcc..10c722913258b 100644 --- a/docs/user-guide/commands/argocd_admin_repo_generate-spec.md +++ b/docs/user-guide/commands/argocd_admin_repo_generate-spec.md @@ -1,3 +1,5 @@ +# `argocd admin repo generate-spec` Command Reference + ## argocd admin repo generate-spec Generate declarative config for a repo @@ -38,6 +40,7 @@ argocd admin repo generate-spec REPOURL [flags] ``` --enable-lfs enable git-lfs (Large File Support) on this repository --enable-oci enable helm-oci (Helm OCI-Based Repository) + --force-http-basic-auth whether to force use of basic auth when connecting repository via HTTP --gcp-service-account-key-path string service account key for the Google Cloud Platform --github-app-enterprise-base-url string base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3 --github-app-id int id of the GitHub Application @@ -65,6 +68,7 @@ argocd admin repo generate-spec REPOURL [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -77,8 +81,12 @@ argocd admin repo generate-spec REPOURL [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_settings.md b/docs/user-guide/commands/argocd_admin_settings.md index e1c9d36f28cd0..3c631cf8f123b 100644 --- a/docs/user-guide/commands/argocd_admin_settings.md +++ b/docs/user-guide/commands/argocd_admin_settings.md @@ -1,3 +1,5 @@ +# `argocd admin settings` Command Reference + ## argocd admin settings Provides set of commands for settings validation and troubleshooting @@ -19,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 @@ -41,6 +44,7 @@ argocd admin settings [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -53,7 +57,11 @@ argocd admin settings [flags] --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 + --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-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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_settings_rbac.md b/docs/user-guide/commands/argocd_admin_settings_rbac.md index 9a1d5f942e314..043c39979a98a 100644 --- a/docs/user-guide/commands/argocd_admin_settings_rbac.md +++ b/docs/user-guide/commands/argocd_admin_settings_rbac.md @@ -1,3 +1,5 @@ +# `argocd admin settings rbac` Command Reference + ## argocd admin settings rbac Validate and test RBAC configuration @@ -29,7 +31,9 @@ argocd admin settings rbac [flags] --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 + --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) @@ -47,9 +51,13 @@ argocd admin settings rbac [flags] --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 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 560539a5239d6..f14092785facf 100644 --- a/docs/user-guide/commands/argocd_admin_settings_rbac_can.md +++ b/docs/user-guide/commands/argocd_admin_settings_rbac_can.md @@ -1,3 +1,5 @@ +# `argocd admin settings rbac can` Command Reference + ## argocd admin settings rbac can Check RBAC permissions for a role or subject @@ -48,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 @@ -75,6 +78,7 @@ argocd admin settings rbac can someuser create application 'default/app' --defau --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -88,7 +92,11 @@ argocd admin settings rbac can someuser create application 'default/app' --defau --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 + --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-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") ``` ### SEE ALSO 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 c68de9ae7ee61..b051c7c63694b 100644 --- a/docs/user-guide/commands/argocd_admin_settings_rbac_validate.md +++ b/docs/user-guide/commands/argocd_admin_settings_rbac_validate.md @@ -1,3 +1,5 @@ +# `argocd admin settings rbac validate` Command Reference + ## argocd admin settings rbac validate Validate RBAC policy @@ -6,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] [--namespace NAMESPACE] [flags] +``` +### Examples ``` -argocd admin settings rbac validate --policy-file=POLICYFILE [flags] + +# 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 @@ -25,43 +66,29 @@ 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. --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) --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 - --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 + --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-crt string Server certificate file - --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 + --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") ``` ### 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 95c67e54dd9c9..eeec6bcf5f63a 100644 --- a/docs/user-guide/commands/argocd_admin_settings_resource-overrides.md +++ b/docs/user-guide/commands/argocd_admin_settings_resource-overrides.md @@ -1,3 +1,5 @@ +# `argocd admin settings resource-overrides` Command Reference + ## argocd admin settings resource-overrides Troubleshoot resource overrides @@ -29,7 +31,9 @@ argocd admin settings resource-overrides [flags] --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 + --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) @@ -47,9 +51,13 @@ argocd admin settings resource-overrides [flags] --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 @@ -61,6 +69,7 @@ argocd admin settings resource-overrides [flags] * [argocd admin settings](argocd_admin_settings.md) - Provides set of commands for settings validation and troubleshooting * [argocd admin settings resource-overrides health](argocd_admin_settings_resource-overrides_health.md) - Assess resource health * [argocd admin settings resource-overrides ignore-differences](argocd_admin_settings_resource-overrides_ignore-differences.md) - Renders fields excluded from diffing +* [argocd admin settings resource-overrides ignore-resource-updates](argocd_admin_settings_resource-overrides_ignore-resource-updates.md) - Renders fields excluded from resource updates * [argocd admin settings resource-overrides list-actions](argocd_admin_settings_resource-overrides_list-actions.md) - List available resource actions * [argocd admin settings resource-overrides run-action](argocd_admin_settings_resource-overrides_run-action.md) - Executes resource action 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 ea98c7badf309..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 @@ -1,3 +1,5 @@ +# `argocd admin settings resource-overrides health` Command Reference + ## argocd admin settings resource-overrides health Assess resource health @@ -40,7 +42,9 @@ argocd admin settings resource-overrides health ./deploy.yaml --argocd-cm-path . --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 + --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) @@ -58,9 +62,13 @@ argocd admin settings resource-overrides health ./deploy.yaml --argocd-cm-path . --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 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 6d5c3ec262942..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 @@ -1,3 +1,5 @@ +# `argocd admin settings resource-overrides ignore-differences` Command Reference + ## argocd admin settings resource-overrides ignore-differences Renders fields excluded from diffing @@ -40,7 +42,9 @@ argocd admin settings resource-overrides ignore-differences ./deploy.yaml --argo --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 + --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) @@ -58,9 +62,13 @@ argocd admin settings resource-overrides ignore-differences ./deploy.yaml --argo --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 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 new file mode 100644 index 0000000000000..69f09208cf42f --- /dev/null +++ b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_ignore-resource-updates.md @@ -0,0 +1,81 @@ +# `argocd admin settings resource-overrides ignore-resource-updates` Command Reference + +## argocd admin settings resource-overrides ignore-resource-updates + +Renders fields excluded from resource updates + +### Synopsis + +Renders ignored fields using the 'ignoreResourceUpdates' setting specified in the 'resource.customizations' field of 'argocd-cm' ConfigMap + +``` +argocd admin settings resource-overrides ignore-resource-updates RESOURCE_YAML_PATH [flags] +``` + +### Examples + +``` + +argocd admin settings resource-overrides ignore-resource-updates ./deploy.yaml --argocd-cm-path ./argocd-cm.yaml +``` + +### Options + +``` + -h, --help help for ignore-resource-updates +``` + +### Options inherited from parent commands + +``` + --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 + --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) + --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 + +* [argocd admin settings resource-overrides](argocd_admin_settings_resource-overrides.md) - Troubleshoot resource overrides + 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 a08acaa1c4ea0..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 @@ -1,3 +1,5 @@ +# `argocd admin settings resource-overrides list-actions` Command Reference + ## argocd admin settings resource-overrides list-actions List available resource actions @@ -40,7 +42,9 @@ argocd admin settings resource-overrides action list /tmp/deploy.yaml --argocd-c --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 + --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) @@ -58,9 +62,13 @@ argocd admin settings resource-overrides action list /tmp/deploy.yaml --argocd-c --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 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 a722fe71eaa87..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 @@ -1,3 +1,5 @@ +# `argocd admin settings resource-overrides run-action` Command Reference + ## argocd admin settings resource-overrides run-action Executes resource action @@ -40,7 +42,9 @@ argocd admin settings resource-overrides action run /tmp/deploy.yaml restart --a --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 + --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) @@ -58,9 +62,13 @@ argocd admin settings resource-overrides action run /tmp/deploy.yaml restart --a --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 diff --git a/docs/user-guide/commands/argocd_admin_settings_validate.md b/docs/user-guide/commands/argocd_admin_settings_validate.md index bc839546a1d0b..8e40a403441b5 100644 --- a/docs/user-guide/commands/argocd_admin_settings_validate.md +++ b/docs/user-guide/commands/argocd_admin_settings_validate.md @@ -1,3 +1,5 @@ +# `argocd admin settings validate` Command Reference + ## argocd admin settings validate Validate settings @@ -24,7 +26,7 @@ argocd admin settings validate --group accounts --group plugins --load-cluster-s ### Options ``` - --group stringArray Optional list of setting groups that have to be validated ( one of: accounts, general, kustomize, plugins, repositories, resource-overrides) + --group stringArray Optional list of setting groups that have to be validated ( one of: accounts, general, kustomize, repositories, resource-overrides) -h, --help help for validate ``` @@ -45,7 +47,9 @@ argocd admin settings validate --group accounts --group plugins --load-cluster-s --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 + --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) @@ -63,9 +67,13 @@ argocd admin settings validate --group accounts --group plugins --load-cluster-s --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 diff --git a/docs/user-guide/commands/argocd_app.md b/docs/user-guide/commands/argocd_app.md index fb421a89527dd..a5878502ce5c7 100644 --- a/docs/user-guide/commands/argocd_app.md +++ b/docs/user-guide/commands/argocd_app.md @@ -1,3 +1,5 @@ +# `argocd app` Command Reference + ## argocd app Manage applications @@ -30,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 @@ -50,6 +53,7 @@ argocd app [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -62,14 +66,19 @@ argocd app [flags] --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 + --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") ``` ### SEE ALSO * [argocd](argocd.md) - argocd controls a Argo CD server * [argocd app actions](argocd_app_actions.md) - Manage Resource actions +* [argocd app add-source](argocd_app_add-source.md) - Adds a source to the list of sources in the application * [argocd app create](argocd_app_create.md) - Create an application * [argocd app delete](argocd_app_delete.md) - Delete an application * [argocd app delete-resource](argocd_app_delete-resource.md) - Delete resource in an application @@ -82,6 +91,7 @@ argocd app [flags] * [argocd app manifests](argocd_app_manifests.md) - Print manifests of an application * [argocd app patch](argocd_app_patch.md) - Patch application * [argocd app patch-resource](argocd_app_patch-resource.md) - Patch resource in an application +* [argocd app remove-source](argocd_app_remove-source.md) - Remove a source from multiple sources application. Index starts with 1. Default value is -1. * [argocd app resources](argocd_app_resources.md) - List resource of application * [argocd app rollback](argocd_app_rollback.md) - Rollback application to a previous deployed version by History ID, omitted will Rollback to the previous version * [argocd app set](argocd_app_set.md) - Set application parameters diff --git a/docs/user-guide/commands/argocd_app_actions.md b/docs/user-guide/commands/argocd_app_actions.md index a2357b2bbf87e..af336f1767b23 100644 --- a/docs/user-guide/commands/argocd_app_actions.md +++ b/docs/user-guide/commands/argocd_app_actions.md @@ -1,3 +1,5 @@ +# `argocd app actions` Command Reference + ## argocd app actions Manage Resource actions @@ -6,6 +8,16 @@ Manage Resource actions argocd app actions [flags] ``` +### Examples + +``` + # List all the available actions for an application + argocd app actions list APPNAME + + # Run an available action for an application + argocd app actions run APPNAME ACTION --kind KIND [--resource-name RESOURCE] [--namespace NAMESPACE] [--group GROUP] +``` + ### Options ``` @@ -19,6 +31,7 @@ argocd app actions [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +44,12 @@ argocd app actions [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_actions_list.md b/docs/user-guide/commands/argocd_app_actions_list.md index 627c33a865544..2d1f78524df50 100644 --- a/docs/user-guide/commands/argocd_app_actions_list.md +++ b/docs/user-guide/commands/argocd_app_actions_list.md @@ -1,3 +1,5 @@ +# `argocd app actions list` Command Reference + ## argocd app actions list Lists available actions on a resource @@ -6,6 +8,13 @@ Lists available actions on a resource argocd app actions list APPNAME [flags] ``` +### Examples + +``` + # List all the available actions for an application + argocd app actions list APPNAME +``` + ### Options ``` @@ -24,6 +33,7 @@ argocd app actions list APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -36,8 +46,12 @@ argocd app actions list APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_actions_run.md b/docs/user-guide/commands/argocd_app_actions_run.md index 8832c1eeb06ea..db8e29fc197b9 100644 --- a/docs/user-guide/commands/argocd_app_actions_run.md +++ b/docs/user-guide/commands/argocd_app_actions_run.md @@ -1,3 +1,5 @@ +# `argocd app actions run` Command Reference + ## argocd app actions run Runs an available action on resource(s) @@ -6,6 +8,13 @@ Runs an available action on resource(s) argocd app actions run APPNAME ACTION [flags] ``` +### Examples + +``` + # Run an available action for an application + argocd app actions run APPNAME ACTION --kind KIND [--resource-name RESOURCE] [--namespace NAMESPACE] [--group GROUP] +``` + ### Options ``` @@ -24,6 +33,7 @@ argocd app actions run APPNAME ACTION [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -36,8 +46,12 @@ argocd app actions run APPNAME ACTION [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_add-source.md b/docs/user-guide/commands/argocd_app_add-source.md new file mode 100644 index 0000000000000..ced4bc7b577ca --- /dev/null +++ b/docs/user-guide/commands/argocd_app_add-source.md @@ -0,0 +1,109 @@ +# `argocd app add-source` Command Reference + +## argocd app add-source + +Adds a source to the list of sources in the application + +``` +argocd app add-source APPNAME [flags] +``` + +### Examples + +``` + # Append a source to the list of sources in the application + argocd app add-source guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook +``` + +### Options + +``` + --allow-empty Set allow zero live resources when sync is automated + -N, --app-namespace string Namespace of the target application where the source will be appended + --auto-prune Set automatic pruning when sync is automated + --config-management-plugin string Config management plugin name + --dest-name string K8s cluster Name (e.g. minikube) + --dest-namespace string K8s target namespace + --dest-server string K8s cluster URL (e.g. https://kubernetes.default.svc) + --directory-exclude string Set glob expression used to exclude files from application source path + --directory-include string Set glob expression used to include files from application source path + --directory-recurse Recurse directory + --env string Application environment to monitor + --helm-chart string Helm Chart name + --helm-pass-credentials Pass credentials to all domain + --helm-set stringArray Helm set values on the command line (can be repeated to set several values: --helm-set key1=val1 --helm-set key2=val2) + --helm-set-file stringArray Helm set values from respective files specified via the command line (can be repeated to set several values: --helm-set-file key1=path1 --helm-set-file key2=path2) + --helm-set-string stringArray Helm set STRING values on the command line (can be repeated to set several values: --helm-set-string key1=val1 --helm-set-string key2=val2) + --helm-skip-crds Skip helm crd installation step + --helm-version string Helm version + -h, --help help for add-source + --ignore-missing-value-files Ignore locally missing valueFiles when setting helm template --values + --jsonnet-ext-var-code stringArray Jsonnet ext var + --jsonnet-ext-var-str stringArray Jsonnet string ext var + --jsonnet-libs stringArray Additional jsonnet libs (prefixed by repoRoot) + --jsonnet-tla-code stringArray Jsonnet top level code arguments + --jsonnet-tla-str stringArray Jsonnet top level string arguments + --kustomize-common-annotation stringArray Set common labels in Kustomize + --kustomize-common-label stringArray Set common labels in Kustomize + --kustomize-force-common-annotation Force common annotations in Kustomize + --kustomize-force-common-label Force common labels in Kustomize + --kustomize-image stringArray Kustomize images (e.g. --kustomize-image node:8.15.0 --kustomize-image mysql=mariadb,alpine@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d) + --kustomize-label-without-selector Do not apply common label to selectors or templates + --kustomize-namespace string Kustomize namespace + --kustomize-replica stringArray Kustomize replicas (e.g. --kustomize-replica my-development=2 --kustomize-replica my-statefulset=4) + --kustomize-version string Kustomize version + --nameprefix string Kustomize nameprefix + --namesuffix string Kustomize namesuffix + -p, --parameter stringArray set a parameter override (e.g. -p guestbook=image=example/guestbook:latest) + --path string Path in repository to the app directory, ignored if a file is set + --plugin-env stringArray Additional plugin envs + --project string Application project name + --ref string Ref is reference to another source within sources field + --release-name string Helm release-name + --repo string Repository URL, ignored if a file is set + --revision string The tracking source branch, tag, commit or Helm chart version the application will sync to + --revision-history-limit int How many items to keep in revision history (default 10) + --self-heal Set self healing when sync is automated + --sync-option Prune=false Add or remove a sync option, e.g add Prune=false. Remove using `!` prefix, e.g. `!Prune=false` + --sync-policy string Set the sync policy (one of: manual (aliases of manual: none), automated (aliases of automated: auto, automatic)) + --sync-retry-backoff-duration duration Sync retry backoff base duration. Input needs to be a duration (e.g. 2m, 1h) (default 5s) + --sync-retry-backoff-factor int Factor multiplies the base duration after each failed sync retry (default 2) + --sync-retry-backoff-max-duration duration Max sync retry backoff duration. Input needs to be a duration (e.g. 2m, 1h) (default 3m0s) + --sync-retry-limit int Max number of allowed sync retries + --validate Validation of repo and cluster (default true) + --values stringArray Helm values file(s) to use + --values-literal-file string Filename or URL to import as a literal Helm values block +``` + +### Options inherited from parent commands + +``` + --auth-token string Authentication token + --client-crt string Client certificate file + --client-crt-key string Client certificate key file + --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. + --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) + --http-retry-max int Maximum number of retries to establish http connection to Argo CD server + --insecure Skip server certificate and domain verification + --kube-context string Directs the command to the given kube-context + --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") + --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 + --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") +``` + +### SEE ALSO + +* [argocd app](argocd_app.md) - Manage applications + diff --git a/docs/user-guide/commands/argocd_app_create.md b/docs/user-guide/commands/argocd_app_create.md index e4e5b1d10c6a8..fb147b8e4aa9f 100644 --- a/docs/user-guide/commands/argocd_app_create.md +++ b/docs/user-guide/commands/argocd_app_create.md @@ -1,3 +1,5 @@ +# `argocd app create` Command Reference + ## argocd app create Create an application @@ -24,6 +26,9 @@ argocd app create APPNAME [flags] # Create a Kustomize app argocd app create kustomize-guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path kustomize-guestbook --dest-namespace default --dest-server https://kubernetes.default.svc --kustomize-image gcr.io/heptio-images/ks-guestbook-demo:0.1 + # Create a MultiSource app while yaml file contains an application with multiple sources + argocd app create guestbook --file + # Create a app using a custom tool: argocd app create kasane --repo https://github.com/argoproj/argocd-example-apps.git --path plugins/kasane --dest-namespace default --dest-server https://kubernetes.default.svc --config-management-plugin kasane ``` @@ -63,6 +68,9 @@ argocd app create APPNAME [flags] --kustomize-force-common-annotation Force common annotations in Kustomize --kustomize-force-common-label Force common labels in Kustomize --kustomize-image stringArray Kustomize images (e.g. --kustomize-image node:8.15.0 --kustomize-image mysql=mariadb,alpine@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d) + --kustomize-label-without-selector Do not apply common label to selectors or templates + --kustomize-namespace string Kustomize namespace + --kustomize-replica stringArray Kustomize replicas (e.g. --kustomize-replica my-development=2 --kustomize-replica my-statefulset=4) --kustomize-version string Kustomize version -l, --label stringArray Labels to apply to the app --name string A name for the app, ignored if a file is set (DEPRECATED) @@ -72,6 +80,7 @@ argocd app create APPNAME [flags] --path string Path in repository to the app directory, ignored if a file is set --plugin-env stringArray Additional plugin envs --project string Application project name + --ref string Ref is reference to another source within sources field --release-name string Helm release-name --repo string Repository URL, ignored if a file is set --revision string The tracking source branch, tag, commit or Helm chart version the application will sync to @@ -79,7 +88,7 @@ argocd app create APPNAME [flags] --self-heal Set self healing when sync is automated --set-finalizer Sets deletion finalizer on the application, application resources will be cascaded on deletion --sync-option Prune=false Add or remove a sync option, e.g add Prune=false. Remove using `!` prefix, e.g. `!Prune=false` - --sync-policy string Set the sync policy (one of: none, automated (aliases of automated: auto, automatic)) + --sync-policy string Set the sync policy (one of: manual (aliases of manual: none), automated (aliases of automated: auto, automatic)) --sync-retry-backoff-duration duration Sync retry backoff base duration. Input needs to be a duration (e.g. 2m, 1h) (default 5s) --sync-retry-backoff-factor int Factor multiplies the base duration after each failed sync retry (default 2) --sync-retry-backoff-max-duration duration Max sync retry backoff duration. Input needs to be a duration (e.g. 2m, 1h) (default 3m0s) @@ -97,6 +106,7 @@ argocd app create APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -109,8 +119,12 @@ argocd app create APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_delete-resource.md b/docs/user-guide/commands/argocd_app_delete-resource.md index 5d3192694a45b..4a305eb4b4489 100644 --- a/docs/user-guide/commands/argocd_app_delete-resource.md +++ b/docs/user-guide/commands/argocd_app_delete-resource.md @@ -1,3 +1,5 @@ +# `argocd app delete-resource` Command Reference + ## argocd app delete-resource Delete resource in an application @@ -16,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 ``` @@ -26,6 +29,7 @@ argocd app delete-resource APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -38,8 +42,12 @@ argocd app delete-resource APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_delete.md b/docs/user-guide/commands/argocd_app_delete.md index 33c5d6c0ee38f..827eeaab4ce7a 100644 --- a/docs/user-guide/commands/argocd_app_delete.md +++ b/docs/user-guide/commands/argocd_app_delete.md @@ -1,3 +1,5 @@ +# `argocd app delete` Command Reference + ## argocd app delete Delete an application @@ -26,10 +28,12 @@ argocd app delete APPNAME [flags] ### Options ``` + -N, --app-namespace string Namespace where the application will be deleted from --cascade Perform a cascaded deletion of all application resources (default true) -h, --help help for delete -p, --propagation-policy string Specify propagation policy for deletion of application's resources. One of: foreground|background (default "foreground") -l, --selector string Delete all apps with matching label. Supports '=', '==', '!=', in, notin, exists & not exists. Matching apps must satisfy all of the specified label constraints. + --wait Wait until deletion of the application(s) completes -y, --yes Turn off prompting to confirm cascaded deletion of application resources ``` @@ -40,6 +44,7 @@ argocd app delete APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -52,8 +57,12 @@ argocd app delete APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_diff.md b/docs/user-guide/commands/argocd_app_diff.md index 6af07a0b08b0f..b352c30123eca 100644 --- a/docs/user-guide/commands/argocd_app_diff.md +++ b/docs/user-guide/commands/argocd_app_diff.md @@ -1,3 +1,5 @@ +# `argocd app diff` Command Reference + ## argocd app diff Perform a diff against the target and live state. @@ -7,6 +9,7 @@ Perform a diff against the target and live state. Perform a diff against the target and live state. Uses 'diff' to render the difference. KUBECTL_EXTERNAL_DIFF environment variable can be used to select your own diff tool. Returns the following exit codes: 2 on general errors, 1 when a diff is found, and 0 when no diff is found +Kubernetes Secrets are ignored from this diff. ``` argocd app diff APPNAME [flags] @@ -15,6 +18,7 @@ argocd app diff APPNAME [flags] ### Options ``` + -N, --app-namespace string Only render the difference in namespace --exit-code Return non-zero exit code when there is a diff (default true) --hard-refresh Refresh application data as well as target manifests cache -h, --help help for diff @@ -33,6 +37,7 @@ argocd app diff APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -45,8 +50,12 @@ argocd app diff APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_edit.md b/docs/user-guide/commands/argocd_app_edit.md index 2f051ab186656..e581677b79c12 100644 --- a/docs/user-guide/commands/argocd_app_edit.md +++ b/docs/user-guide/commands/argocd_app_edit.md @@ -1,3 +1,5 @@ +# `argocd app edit` Command Reference + ## argocd app edit Edit application @@ -9,7 +11,8 @@ argocd app edit APPNAME [flags] ### Options ``` - -h, --help help for edit + -N, --app-namespace string Only edit application in namespace + -h, --help help for edit ``` ### Options inherited from parent commands @@ -19,6 +22,7 @@ argocd app edit APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +35,12 @@ argocd app edit APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_get.md b/docs/user-guide/commands/argocd_app_get.md index 3434d20cb8214..d0bf744054c38 100644 --- a/docs/user-guide/commands/argocd_app_get.md +++ b/docs/user-guide/commands/argocd_app_get.md @@ -1,3 +1,5 @@ +# `argocd app get` Command Reference + ## argocd app get Get application details @@ -6,15 +8,47 @@ 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 ``` - --hard-refresh Refresh application data as well as target manifests cache - -h, --help help for get - -o, --output string Output format. One of: json|yaml|wide (default "wide") - --refresh Refresh application data when retrieving - --show-operation Show application operation - --show-params Show application parameters and overrides + -N, --app-namespace string Only get application from namespace + --hard-refresh Refresh application data as well as target manifests cache + -h, --help help for get + -o, --output string Output format. One of: json|yaml|wide|tree (default "wide") + --refresh Refresh application data when retrieving + --show-operation Show application operation + --show-params Show application parameters and overrides ``` ### Options inherited from parent commands @@ -24,6 +58,7 @@ argocd app get APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -36,8 +71,12 @@ argocd app get APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_history.md b/docs/user-guide/commands/argocd_app_history.md index 7c6a122fad82b..eefadef01f417 100644 --- a/docs/user-guide/commands/argocd_app_history.md +++ b/docs/user-guide/commands/argocd_app_history.md @@ -1,3 +1,5 @@ +# `argocd app history` Command Reference + ## argocd app history Show application deployment history @@ -9,8 +11,9 @@ argocd app history APPNAME [flags] ### Options ``` - -h, --help help for history - -o, --output string Output format. One of: wide|id (default "wide") + -N, --app-namespace string Only show application deployment history in namespace + -h, --help help for history + -o, --output string Output format. One of: wide|id (default "wide") ``` ### Options inherited from parent commands @@ -20,6 +23,7 @@ argocd app history APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +36,12 @@ argocd app history APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_list.md b/docs/user-guide/commands/argocd_app_list.md index 5d85f926815d1..17e00fcac9df3 100644 --- a/docs/user-guide/commands/argocd_app_list.md +++ b/docs/user-guide/commands/argocd_app_list.md @@ -1,3 +1,5 @@ +# `argocd app list` Command Reference + ## argocd app list List applications @@ -39,6 +41,7 @@ argocd app list [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -51,8 +54,12 @@ argocd app list [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_logs.md b/docs/user-guide/commands/argocd_app_logs.md index 473b95a338bfb..8dc1f6a9f1aae 100644 --- a/docs/user-guide/commands/argocd_app_logs.md +++ b/docs/user-guide/commands/argocd_app_logs.md @@ -1,3 +1,5 @@ +# `argocd app logs` Command Reference + ## argocd app logs Get logs of application pods @@ -6,12 +8,52 @@ Get logs of application pods argocd app logs APPNAME [flags] ``` +### Examples + +``` + # Get logs of pods associated with the application "my-app" + argocd app logs my-app + + # Get logs of pods associated with the application "my-app" in a specific resource group + argocd app logs my-app --group my-group + + # Get logs of pods associated with the application "my-app" in a specific resource kind + argocd app logs my-app --kind my-kind + + # Get logs of pods associated with the application "my-app" in a specific namespace + argocd app logs my-app --namespace my-namespace + + # Get logs of pods associated with the application "my-app" for a specific resource name + argocd app logs my-app --name my-resource + + # Stream logs in real-time for the application "my-app" + argocd app logs my-app -f + + # Get the last N lines of logs for the application "my-app" + argocd app logs my-app --tail 100 + + # Get logs since a specified number of seconds ago + argocd app logs my-app --since-seconds 3600 + + # Get logs until a specified time (format: "2023-10-10T15:30:00Z") + argocd app logs my-app --until-time "2023-10-10T15:30:00Z" + + # Filter logs to show only those containing a specific string + argocd app logs my-app --filter "error" + + # Get logs for a specific container within the pods + argocd app logs my-app -c my-container + + # Get previously terminated container logs + argocd app logs my-app -p +``` + ### Options ``` - --container string Optional container name + -c, --container string Optional container name --filter string Show logs contain this string - --follow Specify if the logs should be streamed + -f, --follow Specify if the logs should be streamed --group string Resource group -h, --help help for logs --kind string Resource kind @@ -30,6 +72,7 @@ argocd app logs APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -42,8 +85,12 @@ argocd app logs APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_manifests.md b/docs/user-guide/commands/argocd_app_manifests.md index f73cfc5b9dd29..d3b91756cbe04 100644 --- a/docs/user-guide/commands/argocd_app_manifests.md +++ b/docs/user-guide/commands/argocd_app_manifests.md @@ -1,3 +1,5 @@ +# `argocd app manifests` Command Reference + ## argocd app manifests Print manifests of an application @@ -23,6 +25,7 @@ argocd app manifests APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -35,8 +38,12 @@ argocd app manifests APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_patch-resource.md b/docs/user-guide/commands/argocd_app_patch-resource.md index 95dd5de6cc19b..c849395cb3ea8 100644 --- a/docs/user-guide/commands/argocd_app_patch-resource.md +++ b/docs/user-guide/commands/argocd_app_patch-resource.md @@ -1,3 +1,5 @@ +# `argocd app patch-resource` Command Reference + ## argocd app patch-resource Patch resource in an application @@ -16,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 ``` @@ -26,6 +29,7 @@ argocd app patch-resource APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -38,8 +42,12 @@ argocd app patch-resource APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_patch.md b/docs/user-guide/commands/argocd_app_patch.md index 0174252dccc12..0c453ea159e64 100644 --- a/docs/user-guide/commands/argocd_app_patch.md +++ b/docs/user-guide/commands/argocd_app_patch.md @@ -1,26 +1,30 @@ +# `argocd app patch` Command Reference + ## argocd app patch Patch application -### Synopsis - -Examples: - # Update an application's source path using json patch - argocd app patch myapplication --patch='[{"op": "replace", "path": "/spec/source/path", "value": "newPath"}]' --type json +``` +argocd app patch APPNAME [flags] +``` - # Update an application's repository target revision using merge patch - argocd app patch myapplication --patch '{"spec": { "source": { "targetRevision": "master" } }}' --type merge +### Examples ``` -argocd app patch APPNAME [flags] + # Update an application's source path using json patch + argocd app patch myapplication --patch='[{"op": "replace", "path": "/spec/source/path", "value": "newPath"}]' --type json + + # Update an application's repository target revision using merge patch + argocd app patch myapplication --patch '{"spec": { "source": { "targetRevision": "master" } }}' --type merge ``` ### Options ``` - -h, --help help for patch - --patch string Patch body - --type string The type of patch being provided; one of [json merge] (default "json") + -N, --app-namespace string Only patch application in namespace + -h, --help help for patch + --patch string Patch body + --type string The type of patch being provided; one of [json merge] (default "json") ``` ### Options inherited from parent commands @@ -30,6 +34,7 @@ argocd app patch APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -42,8 +47,12 @@ argocd app patch APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_remove-source.md b/docs/user-guide/commands/argocd_app_remove-source.md new file mode 100644 index 0000000000000..b9f29d8c6eb45 --- /dev/null +++ b/docs/user-guide/commands/argocd_app_remove-source.md @@ -0,0 +1,57 @@ +# `argocd app remove-source` Command Reference + +## argocd app remove-source + +Remove a source from multiple sources application. Index starts with 1. Default value is -1. + +``` +argocd app remove-source APPNAME [flags] +``` + +### Examples + +``` + # Remove the source at index 1 from application's sources. Index starts at 1. + argocd app remove-source myapplication --source-index 1 +``` + +### Options + +``` + -N, --app-namespace string Namespace of the target application where the source will be appended + -h, --help help for remove-source + --source-index int Index of the source from the list of sources of the app. Index starts from 1. (default -1) +``` + +### Options inherited from parent commands + +``` + --auth-token string Authentication token + --client-crt string Client certificate file + --client-crt-key string Client certificate key file + --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. + --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) + --http-retry-max int Maximum number of retries to establish http connection to Argo CD server + --insecure Skip server certificate and domain verification + --kube-context string Directs the command to the given kube-context + --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") + --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 + --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") +``` + +### SEE ALSO + +* [argocd app](argocd_app.md) - Manage applications + diff --git a/docs/user-guide/commands/argocd_app_resources.md b/docs/user-guide/commands/argocd_app_resources.md index 8edb3093f9dd1..22027f74ba3d7 100644 --- a/docs/user-guide/commands/argocd_app_resources.md +++ b/docs/user-guide/commands/argocd_app_resources.md @@ -1,3 +1,5 @@ +# `argocd app resources` Command Reference + ## argocd app resources List resource of application @@ -9,8 +11,10 @@ argocd app resources APPNAME [flags] ### Options ``` - -h, --help help for resources - --orphaned Lists only orphaned 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 @@ -20,6 +24,7 @@ argocd app resources APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +37,12 @@ argocd app resources APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_rollback.md b/docs/user-guide/commands/argocd_app_rollback.md index 80f1d39407dc4..923023e35a2e8 100644 --- a/docs/user-guide/commands/argocd_app_rollback.md +++ b/docs/user-guide/commands/argocd_app_rollback.md @@ -1,3 +1,5 @@ +# `argocd app rollback` Command Reference + ## argocd app rollback Rollback application to a previous deployed version by History ID, omitted will Rollback to the previous version @@ -9,9 +11,11 @@ argocd app rollback APPNAME [ID] [flags] ### Options ``` - -h, --help help for rollback - --prune Allow deleting unexpected resources - --timeout uint Time out after this many seconds + -N, --app-namespace string Rollback application in namespace + -h, --help help for rollback + -o, --output string Output format. One of: json|yaml|wide|tree|tree=detailed (default "wide") + --prune Allow deleting unexpected resources + --timeout uint Time out after this many seconds ``` ### Options inherited from parent commands @@ -21,6 +25,7 @@ argocd app rollback APPNAME [ID] [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -33,8 +38,12 @@ argocd app rollback APPNAME [ID] [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_set.md b/docs/user-guide/commands/argocd_app_set.md index 9e89957e07e9e..97288ad775345 100644 --- a/docs/user-guide/commands/argocd_app_set.md +++ b/docs/user-guide/commands/argocd_app_set.md @@ -1,3 +1,5 @@ +# `argocd app set` Command Reference + ## argocd app set Set application parameters @@ -6,10 +8,33 @@ Set application parameters argocd app set APPNAME [flags] ``` +### Examples + +``` + # Set application parameters for the application "my-app" + argocd app set my-app --parameter key1=value1 --parameter key2=value2 + + # Set and validate application parameters for "my-app" + argocd app set my-app --parameter key1=value1 --parameter key2=value2 --validate + + # Set and override application parameters with JSON or YAML file + argocd app set my-app --from-file path/to/parameters.json + + # Set and override application parameters with a parameter file + argocd app set my-app --parameter-file path/to/parameter-file.yaml + + # Set and override application parameters for a source at index 1 under spec.sources of app my-app. source-index starts at 1. + argocd app set my-app --source-index 1 --repo https://github.com/argoproj/argocd-example-apps.git + + # Set application parameters and specify the namespace + argocd app set my-app --parameter key1=value1 --parameter key2=value2 --namespace my-namespace +``` + ### Options ``` --allow-empty Set allow zero live resources when sync is automated + -N, --app-namespace string Set application parameters in namespace --auto-prune Set automatic pruning when sync is automated --config-management-plugin string Config management plugin name --dest-name string K8s cluster Name (e.g. minikube) @@ -38,6 +63,9 @@ argocd app set APPNAME [flags] --kustomize-force-common-annotation Force common annotations in Kustomize --kustomize-force-common-label Force common labels in Kustomize --kustomize-image stringArray Kustomize images (e.g. --kustomize-image node:8.15.0 --kustomize-image mysql=mariadb,alpine@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d) + --kustomize-label-without-selector Do not apply common label to selectors or templates + --kustomize-namespace string Kustomize namespace + --kustomize-replica stringArray Kustomize replicas (e.g. --kustomize-replica my-development=2 --kustomize-replica my-statefulset=4) --kustomize-version string Kustomize version --nameprefix string Kustomize nameprefix --namesuffix string Kustomize namesuffix @@ -45,13 +73,15 @@ argocd app set APPNAME [flags] --path string Path in repository to the app directory, ignored if a file is set --plugin-env stringArray Additional plugin envs --project string Application project name + --ref string Ref is reference to another source within sources field --release-name string Helm release-name --repo string Repository URL, ignored if a file is set --revision string The tracking source branch, tag, commit or Helm chart version the application will sync to --revision-history-limit int How many items to keep in revision history (default 10) --self-heal Set self healing when sync is automated + --source-index int Index of the source from the list of sources of the app. Index starts at 1. (default -1) --sync-option Prune=false Add or remove a sync option, e.g add Prune=false. Remove using `!` prefix, e.g. `!Prune=false` - --sync-policy string Set the sync policy (one of: none, automated (aliases of automated: auto, automatic)) + --sync-policy string Set the sync policy (one of: manual (aliases of manual: none), automated (aliases of automated: auto, automatic)) --sync-retry-backoff-duration duration Sync retry backoff base duration. Input needs to be a duration (e.g. 2m, 1h) (default 5s) --sync-retry-backoff-factor int Factor multiplies the base duration after each failed sync retry (default 2) --sync-retry-backoff-max-duration duration Max sync retry backoff duration. Input needs to be a duration (e.g. 2m, 1h) (default 3m0s) @@ -68,6 +98,7 @@ argocd app set APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -80,8 +111,12 @@ argocd app set APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_sync.md b/docs/user-guide/commands/argocd_app_sync.md index 798fcecdd8a03..a0a8f8459eeaa 100644 --- a/docs/user-guide/commands/argocd_app_sync.md +++ b/docs/user-guide/commands/argocd_app_sync.md @@ -1,3 +1,5 @@ +# `argocd app sync` Command Reference + ## argocd app sync Sync an application to its target state @@ -36,6 +38,8 @@ argocd app sync [APPNAME... | -l selector | --project project-name] [flags] ### Options ``` + -N, --app-namespace string Only sync an application in namespace + --apply-out-of-sync-only Sync only out-of-sync resources --assumeYes Assume yes as answer for all user queries or prompts --async Do not wait for application to sync before continuing --dry-run Preview apply without affecting cluster @@ -45,6 +49,7 @@ argocd app sync [APPNAME... | -l selector | --project project-name] [flags] --label stringArray Sync only specific resources with a label. This option may be specified repeatedly. --local string Path to a local directory. When this flag is present no git queries will be made --local-repo-root string Path to the repository root. Used together with --local allows setting the repository root (default "/") + -o, --output string Output format. One of: json|yaml|wide|tree|tree=detailed (default "wide") --preview-changes Preview difference against the target and live state before syncing app and wait for user confirmation --project stringArray Sync apps that belong to the specified projects. This option may be specified repeatedly. --prune Allow deleting unexpected resources @@ -68,6 +73,7 @@ argocd app sync [APPNAME... | -l selector | --project project-name] [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -80,8 +86,12 @@ argocd app sync [APPNAME... | -l selector | --project project-name] [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_terminate-op.md b/docs/user-guide/commands/argocd_app_terminate-op.md index fe8475e023aa6..a6d04299ca313 100644 --- a/docs/user-guide/commands/argocd_app_terminate-op.md +++ b/docs/user-guide/commands/argocd_app_terminate-op.md @@ -1,3 +1,5 @@ +# `argocd app terminate-op` Command Reference + ## argocd app terminate-op Terminate running operation of an application @@ -19,6 +21,7 @@ argocd app terminate-op APPNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +34,12 @@ argocd app terminate-op APPNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_unset.md b/docs/user-guide/commands/argocd_app_unset.md index 11d3ae0d7097f..0c3bf25d7fa91 100644 --- a/docs/user-guide/commands/argocd_app_unset.md +++ b/docs/user-guide/commands/argocd_app_unset.md @@ -1,3 +1,5 @@ +# `argocd app unset` Command Reference + ## argocd app unset Unset application parameters @@ -12,9 +14,12 @@ argocd app unset APPNAME parameters [flags] # Unset kustomize override kustomize image argocd app unset my-app --kustomize-image=alpine - # Unset kustomize override prefix + # Unset kustomize override suffix argocd app unset my-app --namesuffix + # Unset kustomize override suffix for source at index 1 under spec.sources of app my-app. source-index starts at 1. + argocd app unset my-app --source-index 1 --namesuffix + # Unset parameter override argocd app unset my-app -p COMPONENT=PARAM ``` @@ -22,17 +27,22 @@ argocd app unset APPNAME parameters [flags] ### Options ``` - -h, --help help for unset - --ignore-missing-value-files Unset the helm ignore-missing-value-files option (revert to false) - --kustomize-image stringArray Kustomize images name (e.g. --kustomize-image node --kustomize-image mysql) - --kustomize-version Kustomize version - --nameprefix Kustomize nameprefix - --namesuffix Kustomize namesuffix - -p, --parameter stringArray Unset a parameter override (e.g. -p guestbook=image) - --pass-credentials Unset passCredentials - --plugin-env stringArray Unset plugin env variables (e.g --plugin-env name) - --values stringArray Unset one or more Helm values files - --values-literal Unset literal Helm values block + -N, --app-namespace string Unset application parameters in namespace + -h, --help help for unset + --ignore-missing-value-files Unset the helm ignore-missing-value-files option (revert to false) + --kustomize-image stringArray Kustomize images name (e.g. --kustomize-image node --kustomize-image mysql) + --kustomize-namespace Kustomize namespace + --kustomize-replica stringArray Kustomize replicas name (e.g. --kustomize-replica my-deployment --kustomize-replica my-statefulset) + --kustomize-version Kustomize version + --nameprefix Kustomize nameprefix + --namesuffix Kustomize namesuffix + -p, --parameter stringArray Unset a parameter override (e.g. -p guestbook=image) + --pass-credentials Unset passCredentials + --plugin-env stringArray Unset plugin env variables (e.g --plugin-env name) + --ref Unset ref on the source + --source-index int Index of the source from the list of sources of the app. Index starts at 1. (default -1) + --values stringArray Unset one or more Helm values files + --values-literal Unset literal Helm values block ``` ### Options inherited from parent commands @@ -42,6 +52,7 @@ argocd app unset APPNAME parameters [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -54,8 +65,12 @@ argocd app unset APPNAME parameters [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_app_wait.md b/docs/user-guide/commands/argocd_app_wait.md index 7bf911acde349..e2d3886f4d3ab 100644 --- a/docs/user-guide/commands/argocd_app_wait.md +++ b/docs/user-guide/commands/argocd_app_wait.md @@ -1,3 +1,5 @@ +# `argocd app wait` Command Reference + ## argocd app wait Wait for an application to reach a synced and healthy state @@ -36,10 +38,13 @@ argocd app wait [APPNAME.. | -l selector] [flags] ### Options ``` + -N, --app-namespace string Only wait for an application in namespace --degraded Wait for degraded + --delete Wait for delete --health Wait for health -h, --help help for wait --operation Wait for pending operations + -o, --output string Output format. One of: json|yaml|wide|tree|tree=detailed (default "wide") --resource stringArray Sync only specific resources as GROUP:KIND:NAME or !GROUP:KIND:NAME. Fields may be blank and '*' can be used. This option may be specified repeatedly -l, --selector string Wait for apps by label. Supports '=', '==', '!=', in, notin, exists & not exists. Matching apps must satisfy all of the specified label constraints. --suspended Wait for suspended @@ -54,6 +59,7 @@ argocd app wait [APPNAME.. | -l selector] [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -66,8 +72,12 @@ argocd app wait [APPNAME.. | -l selector] [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_appset.md b/docs/user-guide/commands/argocd_appset.md index a3af8b8f50002..7b543ae318831 100644 --- a/docs/user-guide/commands/argocd_appset.md +++ b/docs/user-guide/commands/argocd_appset.md @@ -1,3 +1,5 @@ +# `argocd appset` Command Reference + ## argocd appset Manage ApplicationSets @@ -33,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 @@ -53,6 +56,7 @@ argocd appset [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -65,8 +69,12 @@ argocd appset [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_appset_create.md b/docs/user-guide/commands/argocd_appset_create.md index 07666ae70b295..fccc03fcc971c 100644 --- a/docs/user-guide/commands/argocd_appset_create.md +++ b/docs/user-guide/commands/argocd_appset_create.md @@ -1,3 +1,5 @@ +# `argocd appset create` Command Reference + ## argocd appset create Create one or more ApplicationSets @@ -27,6 +29,7 @@ argocd appset create [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -39,8 +42,12 @@ argocd appset create [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_appset_delete.md b/docs/user-guide/commands/argocd_appset_delete.md index 9c991e9c33f42..d97ca51b604e8 100644 --- a/docs/user-guide/commands/argocd_appset_delete.md +++ b/docs/user-guide/commands/argocd_appset_delete.md @@ -1,3 +1,5 @@ +# `argocd appset delete` Command Reference + ## argocd appset delete Delete one or more ApplicationSets @@ -27,6 +29,7 @@ argocd appset delete [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -39,8 +42,12 @@ argocd appset delete [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_appset_get.md b/docs/user-guide/commands/argocd_appset_get.md index 4c791524f988a..8024d8ebf0a06 100644 --- a/docs/user-guide/commands/argocd_appset_get.md +++ b/docs/user-guide/commands/argocd_appset_get.md @@ -1,3 +1,5 @@ +# `argocd appset get` Command Reference + ## argocd appset get Get ApplicationSet details @@ -6,6 +8,13 @@ Get ApplicationSet details argocd appset get APPSETNAME [flags] ``` +### Examples + +``` + # Get ApplicationSets + argocd appset get APPSETNAME +``` + ### Options ``` @@ -21,6 +30,7 @@ argocd appset get APPSETNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -33,8 +43,12 @@ argocd appset get APPSETNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_appset_list.md b/docs/user-guide/commands/argocd_appset_list.md index 1320ccc1b7883..92e0b21cb749b 100644 --- a/docs/user-guide/commands/argocd_appset_list.md +++ b/docs/user-guide/commands/argocd_appset_list.md @@ -1,3 +1,5 @@ +# `argocd appset list` Command Reference + ## argocd appset list List ApplicationSets @@ -16,10 +18,11 @@ argocd appset list [flags] ### Options ``` - -h, --help help for list - -o, --output string Output format. One of: wide|name|json|yaml (default "wide") - -p, --project stringArray Filter by project name - -l, --selector string List applicationsets by label + -N, --appset-namespace string Only list applicationsets in namespace + -h, --help help for list + -o, --output string Output format. One of: wide|name|json|yaml (default "wide") + -p, --project stringArray Filter by project name + -l, --selector string List applicationsets by label ``` ### Options inherited from parent commands @@ -29,6 +32,7 @@ argocd appset list [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -41,8 +45,12 @@ argocd appset list [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_cert.md b/docs/user-guide/commands/argocd_cert.md index 830434528237e..b126328a4372f 100644 --- a/docs/user-guide/commands/argocd_cert.md +++ b/docs/user-guide/commands/argocd_cert.md @@ -1,3 +1,5 @@ +# `argocd cert` Command Reference + ## argocd cert Manage repository certificates and SSH known hosts entries @@ -40,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 @@ -60,6 +63,7 @@ argocd cert [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -72,8 +76,12 @@ argocd cert [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_cert_add-ssh.md b/docs/user-guide/commands/argocd_cert_add-ssh.md index 8fdd6bf655d63..94daf24bf376e 100644 --- a/docs/user-guide/commands/argocd_cert_add-ssh.md +++ b/docs/user-guide/commands/argocd_cert_add-ssh.md @@ -1,3 +1,5 @@ +# `argocd cert add-ssh` Command Reference + ## argocd cert add-ssh Add SSH known host entries for repository servers @@ -22,6 +24,7 @@ argocd cert add-ssh --batch [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -34,8 +37,12 @@ argocd cert add-ssh --batch [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_cert_add-tls.md b/docs/user-guide/commands/argocd_cert_add-tls.md index 0500e19c071dd..e8d3d733697e7 100644 --- a/docs/user-guide/commands/argocd_cert_add-tls.md +++ b/docs/user-guide/commands/argocd_cert_add-tls.md @@ -1,3 +1,5 @@ +# `argocd cert add-tls` Command Reference + ## argocd cert add-tls Add TLS certificate data for connecting to repository server SERVERNAME @@ -9,7 +11,7 @@ argocd cert add-tls SERVERNAME [flags] ### Options ``` - --from string read TLS certificate data from file (default is to read from stdin) + --from string Read TLS certificate data from file (default is to read from stdin) -h, --help help for add-tls --upsert Replace existing TLS certificate if certificate is different in input ``` @@ -21,6 +23,7 @@ argocd cert add-tls SERVERNAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -33,8 +36,12 @@ argocd cert add-tls SERVERNAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_cert_list.md b/docs/user-guide/commands/argocd_cert_list.md index 8aed9cc7ab61f..43a4af5bea783 100644 --- a/docs/user-guide/commands/argocd_cert_list.md +++ b/docs/user-guide/commands/argocd_cert_list.md @@ -1,3 +1,5 @@ +# `argocd cert list` Command Reference + ## argocd cert list List configured certificates @@ -9,11 +11,11 @@ argocd cert list [flags] ### Options ``` - --cert-type string only list certificates of given type, valid: 'ssh','https' + --cert-type string Only list certificates of given type, valid: 'ssh','https' -h, --help help for list - --hostname-pattern string only list certificates for hosts matching given glob-pattern + --hostname-pattern string Only list certificates for hosts matching given glob-pattern -o, --output string Output format. One of: json|yaml|wide (default "wide") - --sort string set display sort order for output format wide. One of: hostname|type + --sort string Set display sort order for output format wide. One of: hostname|type ``` ### Options inherited from parent commands @@ -23,6 +25,7 @@ argocd cert list [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -35,8 +38,12 @@ argocd cert list [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_cert_rm.md b/docs/user-guide/commands/argocd_cert_rm.md index 1baad03d7ea3e..602a84aa6b85c 100644 --- a/docs/user-guide/commands/argocd_cert_rm.md +++ b/docs/user-guide/commands/argocd_cert_rm.md @@ -1,3 +1,5 @@ +# `argocd cert rm` Command Reference + ## argocd cert rm Remove certificate of TYPE for REPOSERVER @@ -21,6 +23,7 @@ argocd cert rm REPOSERVER [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -33,8 +36,12 @@ argocd cert rm REPOSERVER [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_cluster.md b/docs/user-guide/commands/argocd_cluster.md index f9c1681a82475..a30c357d54d71 100644 --- a/docs/user-guide/commands/argocd_cluster.md +++ b/docs/user-guide/commands/argocd_cluster.md @@ -1,3 +1,5 @@ +# `argocd cluster` Command Reference + ## argocd cluster Manage cluster credentials @@ -37,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 @@ -57,6 +60,7 @@ argocd cluster [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -69,8 +73,12 @@ argocd cluster [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_cluster_add.md b/docs/user-guide/commands/argocd_cluster_add.md index 827b3344eb81c..8a80a12f5a4d5 100644 --- a/docs/user-guide/commands/argocd_cluster_add.md +++ b/docs/user-guide/commands/argocd_cluster_add.md @@ -1,3 +1,5 @@ +# `argocd cluster add` Command Reference + ## argocd cluster add argocd cluster add CONTEXT @@ -11,7 +13,9 @@ 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. --exec-command string Command to run to provide client credentials to the cluster. You may need to build a custom ArgoCD image to ensure the command is available at runtime. --exec-command-api-version string Preferred input version of the ExecInfo for the --exec-command executable @@ -39,6 +43,7 @@ argocd cluster add CONTEXT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -51,8 +56,12 @@ argocd cluster add CONTEXT [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_cluster_get.md b/docs/user-guide/commands/argocd_cluster_get.md index b4e172d511da7..a020a94557e99 100644 --- a/docs/user-guide/commands/argocd_cluster_get.md +++ b/docs/user-guide/commands/argocd_cluster_get.md @@ -1,3 +1,5 @@ +# `argocd cluster get` Command Reference + ## argocd cluster get Get cluster information @@ -27,6 +29,7 @@ argocd cluster get in-cluster --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -39,8 +42,12 @@ argocd cluster get in-cluster --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_cluster_list.md b/docs/user-guide/commands/argocd_cluster_list.md index 7683c909e59d2..9779a4fb8af0b 100644 --- a/docs/user-guide/commands/argocd_cluster_list.md +++ b/docs/user-guide/commands/argocd_cluster_list.md @@ -1,3 +1,5 @@ +# `argocd cluster list` Command Reference + ## argocd cluster list List configured clusters @@ -6,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 ``` @@ -20,6 +44,7 @@ argocd cluster list [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +57,12 @@ argocd cluster list [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_cluster_rm.md b/docs/user-guide/commands/argocd_cluster_rm.md index 9c17e3f5f56c5..80057bb5a7082 100644 --- a/docs/user-guide/commands/argocd_cluster_rm.md +++ b/docs/user-guide/commands/argocd_cluster_rm.md @@ -1,3 +1,5 @@ +# `argocd cluster rm` Command Reference + ## argocd cluster rm Remove cluster credentials @@ -27,6 +29,7 @@ argocd cluster rm cluster-name --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -39,8 +42,12 @@ argocd cluster rm cluster-name --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_cluster_rotate-auth.md b/docs/user-guide/commands/argocd_cluster_rotate-auth.md index 41ca1015bc9c2..8dc3a5bf745d3 100644 --- a/docs/user-guide/commands/argocd_cluster_rotate-auth.md +++ b/docs/user-guide/commands/argocd_cluster_rotate-auth.md @@ -1,3 +1,5 @@ +# `argocd cluster rotate-auth` Command Reference + ## argocd cluster rotate-auth argocd cluster rotate-auth SERVER/NAME @@ -26,6 +28,7 @@ argocd cluster rotate-auth cluster-name --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -38,8 +41,12 @@ argocd cluster rotate-auth cluster-name --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_cluster_set.md b/docs/user-guide/commands/argocd_cluster_set.md index f1099fd6e3cc3..2dba9c2ad16e8 100644 --- a/docs/user-guide/commands/argocd_cluster_set.md +++ b/docs/user-guide/commands/argocd_cluster_set.md @@ -1,3 +1,5 @@ +# `argocd cluster set` Command Reference + ## argocd cluster set Set cluster information @@ -29,6 +31,7 @@ argocd cluster set NAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -41,8 +44,12 @@ argocd cluster set NAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_completion.md b/docs/user-guide/commands/argocd_completion.md index 24c838913be1e..3d6d981ef4c8f 100644 --- a/docs/user-guide/commands/argocd_completion.md +++ b/docs/user-guide/commands/argocd_completion.md @@ -1,3 +1,5 @@ +# `argocd completion` Command Reference + ## argocd completion output shell completion code for the specified shell (bash or zsh) @@ -11,14 +13,31 @@ To access completions in your current shell, run $ source <(argocd completion bash) Alternatively, write it to a file and source in .bash_profile -For zsh, output to a file in a directory referenced by the $fpath shell -variable. +For zsh, add the following to your ~/.zshrc file: +source <(argocd completion zsh) +compdef _argocd argocd + +Optionally, also add the following, in case you are getting errors involving compdef & compinit such as command not found: compdef: +autoload -Uz compinit +compinit ``` argocd completion SHELL [flags] ``` +### Examples + +``` +# For bash +$ source <(argocd completion bash) + +# For zsh +$ argocd completion zsh > _argocd +$ source _argocd + +``` + ### Options ``` @@ -32,6 +51,7 @@ argocd completion SHELL [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -44,8 +64,12 @@ argocd completion SHELL [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_context.md b/docs/user-guide/commands/argocd_context.md index 91ff497679855..f02944cf4f775 100644 --- a/docs/user-guide/commands/argocd_context.md +++ b/docs/user-guide/commands/argocd_context.md @@ -1,3 +1,5 @@ +# `argocd context` Command Reference + ## argocd context Switch between contexts @@ -6,6 +8,19 @@ Switch between contexts argocd context [CONTEXT] [flags] ``` +### Examples + +``` +# List Argo CD Contexts +argocd context + +# Switch Argo CD context +argocd context cd.argoproj.io + +# Delete Argo CD context +argocd context cd.argoproj.io --delete +``` + ### Options ``` @@ -20,6 +35,7 @@ argocd context [CONTEXT] [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +48,12 @@ argocd context [CONTEXT] [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_gpg.md b/docs/user-guide/commands/argocd_gpg.md index 99549701187e6..bca15e98b7c87 100644 --- a/docs/user-guide/commands/argocd_gpg.md +++ b/docs/user-guide/commands/argocd_gpg.md @@ -1,3 +1,5 @@ +# `argocd gpg` Command Reference + ## argocd gpg Manage GPG keys used for signature verification @@ -17,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 @@ -37,6 +40,7 @@ argocd gpg [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -49,8 +53,12 @@ argocd gpg [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_gpg_add.md b/docs/user-guide/commands/argocd_gpg_add.md index 9fb856d150cbc..3ef5d4e6c72d5 100644 --- a/docs/user-guide/commands/argocd_gpg_add.md +++ b/docs/user-guide/commands/argocd_gpg_add.md @@ -1,3 +1,5 @@ +# `argocd gpg add` Command Reference + ## argocd gpg add Adds a GPG public key to the server's keyring @@ -6,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 ``` @@ -20,6 +29,7 @@ argocd gpg add [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +42,12 @@ argocd gpg add [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_gpg_get.md b/docs/user-guide/commands/argocd_gpg_get.md index 4cd1e78f59426..e0ad3d9ee25d6 100644 --- a/docs/user-guide/commands/argocd_gpg_get.md +++ b/docs/user-guide/commands/argocd_gpg_get.md @@ -1,3 +1,5 @@ +# `argocd gpg get` Command Reference + ## argocd gpg get Get the GPG public key with ID from the server @@ -6,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 ``` @@ -20,6 +35,7 @@ argocd gpg get KEYID [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +48,12 @@ argocd gpg get KEYID [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_gpg_list.md b/docs/user-guide/commands/argocd_gpg_list.md index 0064c780dc652..50f0e72e83c0d 100644 --- a/docs/user-guide/commands/argocd_gpg_list.md +++ b/docs/user-guide/commands/argocd_gpg_list.md @@ -1,3 +1,5 @@ +# `argocd gpg list` Command Reference + ## argocd gpg list List configured GPG public keys @@ -6,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 ``` @@ -20,6 +35,7 @@ argocd gpg list [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +48,12 @@ argocd gpg list [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_gpg_rm.md b/docs/user-guide/commands/argocd_gpg_rm.md index d84def9d2c2fc..ecf744988d0fd 100644 --- a/docs/user-guide/commands/argocd_gpg_rm.md +++ b/docs/user-guide/commands/argocd_gpg_rm.md @@ -1,3 +1,5 @@ +# `argocd gpg rm` Command Reference + ## argocd gpg rm Removes a GPG public key from the server's keyring @@ -19,6 +21,7 @@ argocd gpg rm KEYID [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +34,12 @@ argocd gpg rm KEYID [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_login.md b/docs/user-guide/commands/argocd_login.md index d99a6b433313a..adf02fefbc454 100644 --- a/docs/user-guide/commands/argocd_login.md +++ b/docs/user-guide/commands/argocd_login.md @@ -1,3 +1,5 @@ +# `argocd login` Command Reference + ## argocd login Log in to Argo CD @@ -27,12 +29,12 @@ argocd login cd.argoproj.io --core ``` -h, --help help for login - --name string name to use for the context - --password string the password of an account to authenticate + --name string Name to use for the context + --password string The password of an account to authenticate --skip-test-tls Skip testing whether the server is configured with TLS (this can help when the command hangs for no apparent reason) - --sso perform SSO login - --sso-port int port to run local OAuth2 login application (default 8085) - --username string the username of an account to authenticate + --sso Perform SSO login + --sso-port int Port to run local OAuth2 login application (default 8085) + --username string The username of an account to authenticate ``` ### Options inherited from parent commands @@ -42,6 +44,7 @@ argocd login cd.argoproj.io --core --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -54,8 +57,12 @@ argocd login cd.argoproj.io --core --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_logout.md b/docs/user-guide/commands/argocd_logout.md index aa8dc75f463d5..3e18c70a063a0 100644 --- a/docs/user-guide/commands/argocd_logout.md +++ b/docs/user-guide/commands/argocd_logout.md @@ -1,3 +1,5 @@ +# `argocd logout` Command Reference + ## argocd logout Log out from Argo CD @@ -10,6 +12,15 @@ Log out from Argo CD argocd logout CONTEXT [flags] ``` +### Examples + +``` +# To log out of argocd +$ argocd logout +# This can be helpful for security reasons or when you want to switch between different Argo CD contexts or accounts. + +``` + ### Options ``` @@ -23,6 +34,7 @@ argocd logout CONTEXT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -35,8 +47,12 @@ argocd logout CONTEXT [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj.md b/docs/user-guide/commands/argocd_proj.md index 549d08ec8f77b..5586463adee6e 100644 --- a/docs/user-guide/commands/argocd_proj.md +++ b/docs/user-guide/commands/argocd_proj.md @@ -1,3 +1,5 @@ +# `argocd proj` Command Reference + ## argocd proj Manage projects @@ -6,6 +8,22 @@ Manage projects argocd proj [flags] ``` +### Examples + +``` + # List all available projects + argocd proj list + + # Create a new project with name PROJECT + argocd proj create PROJECT + + # Delete the project with name PROJECT + argocd proj delete PROJECT + + # Edit the information on project with name PROJECT + argocd proj edit PROJECT +``` + ### Options ``` @@ -17,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 @@ -37,6 +56,7 @@ argocd proj [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -49,8 +69,12 @@ argocd proj [flags] --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 + --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") ``` ### SEE ALSO @@ -60,6 +84,7 @@ argocd proj [flags] * [argocd proj add-orphaned-ignore](argocd_proj_add-orphaned-ignore.md) - Add a resource to orphaned ignore list * [argocd proj add-signature-key](argocd_proj_add-signature-key.md) - Add GnuPG signature key to project * [argocd proj add-source](argocd_proj_add-source.md) - Add project source repository +* [argocd proj add-source-namespace](argocd_proj_add-source-namespace.md) - Add source namespace to the AppProject * [argocd proj allow-cluster-resource](argocd_proj_allow-cluster-resource.md) - Adds a cluster-scoped API resource to the allow list and removes it from deny list * [argocd proj allow-namespace-resource](argocd_proj_allow-namespace-resource.md) - Removes a namespaced API resource from the deny list or add a namespaced API resource to the allow list * [argocd proj create](argocd_proj_create.md) - Create a project @@ -73,6 +98,7 @@ argocd proj [flags] * [argocd proj remove-orphaned-ignore](argocd_proj_remove-orphaned-ignore.md) - Remove a resource from orphaned ignore list * [argocd proj remove-signature-key](argocd_proj_remove-signature-key.md) - Remove GnuPG signature key from project * [argocd proj remove-source](argocd_proj_remove-source.md) - Remove project source repository +* [argocd proj remove-source-namespace](argocd_proj_remove-source-namespace.md) - Removes the source namespace from the AppProject * [argocd proj role](argocd_proj_role.md) - Manage a project's roles * [argocd proj set](argocd_proj_set.md) - Set project parameters * [argocd proj windows](argocd_proj_windows.md) - Manage a project's sync windows diff --git a/docs/user-guide/commands/argocd_proj_add-destination.md b/docs/user-guide/commands/argocd_proj_add-destination.md index 03a287d50886d..688aebf84156e 100644 --- a/docs/user-guide/commands/argocd_proj_add-destination.md +++ b/docs/user-guide/commands/argocd_proj_add-destination.md @@ -1,3 +1,5 @@ +# `argocd proj add-destination` Command Reference + ## argocd proj add-destination Add project destination @@ -6,6 +8,16 @@ Add project destination argocd proj add-destination PROJECT SERVER/NAME NAMESPACE [flags] ``` +### Examples + +``` + # Add project destination using a server URL (SERVER) in the specified namespace (NAMESPACE) on the project with name PROJECT + argocd proj add-destination PROJECT SERVER NAMESPACE + + # Add project destination using a server name (NAME) in the specified namespace (NAMESPACE) on the project with name PROJECT + argocd proj add-destination PROJECT NAME NAMESPACE --name +``` + ### Options ``` @@ -20,6 +32,7 @@ argocd proj add-destination PROJECT SERVER/NAME NAMESPACE [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +45,12 @@ argocd proj add-destination PROJECT SERVER/NAME NAMESPACE [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_add-orphaned-ignore.md b/docs/user-guide/commands/argocd_proj_add-orphaned-ignore.md index ed4b0ca5142cc..1b36d8a5ff0f1 100644 --- a/docs/user-guide/commands/argocd_proj_add-orphaned-ignore.md +++ b/docs/user-guide/commands/argocd_proj_add-orphaned-ignore.md @@ -1,3 +1,5 @@ +# `argocd proj add-orphaned-ignore` Command Reference + ## argocd proj add-orphaned-ignore Add a resource to orphaned ignore list @@ -6,6 +8,16 @@ Add a resource to orphaned ignore list argocd proj add-orphaned-ignore PROJECT GROUP KIND [flags] ``` +### Examples + +``` + # Add a resource of the specified GROUP and KIND to orphaned ignore list on the project with name PROJECT + argocd proj add-orphaned-ignore PROJECT GROUP KIND + + # Add resources of the specified GROUP and KIND using a NAME pattern to orphaned ignore list on the project with name PROJECT + argocd proj add-orphaned-ignore PROJECT GROUP KIND --name NAME +``` + ### Options ``` @@ -20,6 +32,7 @@ argocd proj add-orphaned-ignore PROJECT GROUP KIND [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +45,12 @@ argocd proj add-orphaned-ignore PROJECT GROUP KIND [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_add-signature-key.md b/docs/user-guide/commands/argocd_proj_add-signature-key.md index c594fccc1343a..404660510700b 100644 --- a/docs/user-guide/commands/argocd_proj_add-signature-key.md +++ b/docs/user-guide/commands/argocd_proj_add-signature-key.md @@ -1,3 +1,5 @@ +# `argocd proj add-signature-key` Command Reference + ## argocd proj add-signature-key Add GnuPG signature key to project @@ -6,6 +8,13 @@ Add GnuPG signature key to project argocd proj add-signature-key PROJECT KEY-ID [flags] ``` +### Examples + +``` + # Add GnuPG signature key KEY-ID to project PROJECT + argocd proj add-signature-key PROJECT KEY-ID +``` + ### Options ``` @@ -19,6 +28,7 @@ argocd proj add-signature-key PROJECT KEY-ID [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +41,12 @@ argocd proj add-signature-key PROJECT KEY-ID [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_add-source-namespace.md b/docs/user-guide/commands/argocd_proj_add-source-namespace.md new file mode 100644 index 0000000000000..ced1f6fa3c67d --- /dev/null +++ b/docs/user-guide/commands/argocd_proj_add-source-namespace.md @@ -0,0 +1,55 @@ +# `argocd proj add-source-namespace` Command Reference + +## argocd proj add-source-namespace + +Add source namespace to the AppProject + +``` +argocd proj add-source-namespace PROJECT NAMESPACE [flags] +``` + +### Examples + +``` + # Add Kubernetes namespace as source namespace to the AppProject where application resources are allowed to be created in. + argocd proj add-source-namespace PROJECT NAMESPACE +``` + +### Options + +``` + -h, --help help for add-source-namespace +``` + +### Options inherited from parent commands + +``` + --auth-token string Authentication token + --client-crt string Client certificate file + --client-crt-key string Client certificate key file + --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. + --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) + --http-retry-max int Maximum number of retries to establish http connection to Argo CD server + --insecure Skip server certificate and domain verification + --kube-context string Directs the command to the given kube-context + --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") + --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 + --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") +``` + +### SEE ALSO + +* [argocd proj](argocd_proj.md) - Manage projects + diff --git a/docs/user-guide/commands/argocd_proj_add-source.md b/docs/user-guide/commands/argocd_proj_add-source.md index c74a056a43654..f0c2f18fd9792 100644 --- a/docs/user-guide/commands/argocd_proj_add-source.md +++ b/docs/user-guide/commands/argocd_proj_add-source.md @@ -1,3 +1,5 @@ +# `argocd proj add-source` Command Reference + ## argocd proj add-source Add project source repository @@ -6,6 +8,13 @@ Add project source repository argocd proj add-source PROJECT URL [flags] ``` +### Examples + +``` + # Add a source repository (URL) to the project with name PROJECT + argocd proj add-source PROJECT URL +``` + ### Options ``` @@ -19,6 +28,7 @@ argocd proj add-source PROJECT URL [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +41,12 @@ argocd proj add-source PROJECT URL [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_allow-cluster-resource.md b/docs/user-guide/commands/argocd_proj_allow-cluster-resource.md index ad1c2a641f9a8..338027e724bc2 100644 --- a/docs/user-guide/commands/argocd_proj_allow-cluster-resource.md +++ b/docs/user-guide/commands/argocd_proj_allow-cluster-resource.md @@ -1,3 +1,5 @@ +# `argocd proj allow-cluster-resource` Command Reference + ## argocd proj allow-cluster-resource Adds a cluster-scoped API resource to the allow list and removes it from deny list @@ -6,6 +8,13 @@ Adds a cluster-scoped API resource to the allow list and removes it from deny li argocd proj allow-cluster-resource PROJECT GROUP KIND [flags] ``` +### Examples + +``` + # Adds a cluster-scoped API resource with specified GROUP and KIND to the allow list and removes it from deny list for project PROJECT + argocd proj allow-cluster-resource PROJECT GROUP KIND +``` + ### Options ``` @@ -20,6 +29,7 @@ argocd proj allow-cluster-resource PROJECT GROUP KIND [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +42,12 @@ argocd proj allow-cluster-resource PROJECT GROUP KIND [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_allow-namespace-resource.md b/docs/user-guide/commands/argocd_proj_allow-namespace-resource.md index bd1783892a751..3e4a410f32a47 100644 --- a/docs/user-guide/commands/argocd_proj_allow-namespace-resource.md +++ b/docs/user-guide/commands/argocd_proj_allow-namespace-resource.md @@ -1,3 +1,5 @@ +# `argocd proj allow-namespace-resource` Command Reference + ## argocd proj allow-namespace-resource Removes a namespaced API resource from the deny list or add a namespaced API resource to the allow list @@ -6,6 +8,13 @@ Removes a namespaced API resource from the deny list or add a namespaced API res argocd proj allow-namespace-resource PROJECT GROUP KIND [flags] ``` +### Examples + +``` + # Removes a namespaced API resource with specified GROUP and KIND from the deny list or add a namespaced API resource to the allow list for project PROJECT + argocd proj allow-namespace-resource PROJECT GROUP KIND +``` + ### Options ``` @@ -20,6 +29,7 @@ argocd proj allow-namespace-resource PROJECT GROUP KIND [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +42,12 @@ argocd proj allow-namespace-resource PROJECT GROUP KIND [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_create.md b/docs/user-guide/commands/argocd_proj_create.md index fa9ac85afe9f5..fd8687c1b2982 100644 --- a/docs/user-guide/commands/argocd_proj_create.md +++ b/docs/user-guide/commands/argocd_proj_create.md @@ -1,3 +1,5 @@ +# `argocd proj create` Command Reference + ## argocd proj create Create a project @@ -6,6 +8,16 @@ Create a project argocd proj create PROJECT [flags] ``` +### Examples + +``` + # 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 + argocd proj create PROJECT -f FILE|URL +``` + ### Options ``` @@ -32,6 +44,7 @@ argocd proj create PROJECT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -44,8 +57,12 @@ argocd proj create PROJECT [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_delete.md b/docs/user-guide/commands/argocd_proj_delete.md index a36b57aeb9455..4d6c4a94f609c 100644 --- a/docs/user-guide/commands/argocd_proj_delete.md +++ b/docs/user-guide/commands/argocd_proj_delete.md @@ -1,3 +1,5 @@ +# `argocd proj delete` Command Reference + ## argocd proj delete Delete project @@ -6,6 +8,13 @@ Delete project argocd proj delete PROJECT [flags] ``` +### Examples + +``` + # Delete the project with name PROJECT + argocd proj delete PROJECT +``` + ### Options ``` @@ -19,6 +28,7 @@ argocd proj delete PROJECT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +41,12 @@ argocd proj delete PROJECT [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_deny-cluster-resource.md b/docs/user-guide/commands/argocd_proj_deny-cluster-resource.md index 25db97712b0db..4621b18c3efe1 100644 --- a/docs/user-guide/commands/argocd_proj_deny-cluster-resource.md +++ b/docs/user-guide/commands/argocd_proj_deny-cluster-resource.md @@ -1,3 +1,5 @@ +# `argocd proj deny-cluster-resource` Command Reference + ## argocd proj deny-cluster-resource Removes a cluster-scoped API resource from the allow list and adds it to deny list @@ -6,6 +8,13 @@ Removes a cluster-scoped API resource from the allow list and adds it to deny li argocd proj deny-cluster-resource PROJECT GROUP KIND [flags] ``` +### Examples + +``` + # Removes a cluster-scoped API resource with specified GROUP and KIND from the allow list and adds it to deny list for project PROJECT + argocd proj deny-cluster-resource PROJECT GROUP KIND +``` + ### Options ``` @@ -20,6 +29,7 @@ argocd proj deny-cluster-resource PROJECT GROUP KIND [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +42,12 @@ argocd proj deny-cluster-resource PROJECT GROUP KIND [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_deny-namespace-resource.md b/docs/user-guide/commands/argocd_proj_deny-namespace-resource.md index bf4fa77797d87..e8b55a7b0adb6 100644 --- a/docs/user-guide/commands/argocd_proj_deny-namespace-resource.md +++ b/docs/user-guide/commands/argocd_proj_deny-namespace-resource.md @@ -1,3 +1,5 @@ +# `argocd proj deny-namespace-resource` Command Reference + ## argocd proj deny-namespace-resource Adds a namespaced API resource to the deny list or removes a namespaced API resource from the allow list @@ -6,6 +8,13 @@ Adds a namespaced API resource to the deny list or removes a namespaced API reso argocd proj deny-namespace-resource PROJECT GROUP KIND [flags] ``` +### Examples + +``` + # Adds a namespaced API resource with specified GROUP and KIND from the deny list or removes a namespaced API resource from the allow list for project PROJECT + argocd proj deny-namespace-resource PROJECT GROUP KIND +``` + ### Options ``` @@ -20,6 +29,7 @@ argocd proj deny-namespace-resource PROJECT GROUP KIND [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +42,12 @@ argocd proj deny-namespace-resource PROJECT GROUP KIND [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_edit.md b/docs/user-guide/commands/argocd_proj_edit.md index 170fc5abfa8e0..63a584accfad8 100644 --- a/docs/user-guide/commands/argocd_proj_edit.md +++ b/docs/user-guide/commands/argocd_proj_edit.md @@ -1,3 +1,5 @@ +# `argocd proj edit` Command Reference + ## argocd proj edit Edit project @@ -6,6 +8,13 @@ Edit project argocd proj edit PROJECT [flags] ``` +### Examples + +``` + # Edit the information on project with name PROJECT + argocd proj edit PROJECT +``` + ### Options ``` @@ -19,6 +28,7 @@ argocd proj edit PROJECT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +41,12 @@ argocd proj edit PROJECT [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_get.md b/docs/user-guide/commands/argocd_proj_get.md index d9feeeffab02d..2d2e437b79779 100644 --- a/docs/user-guide/commands/argocd_proj_get.md +++ b/docs/user-guide/commands/argocd_proj_get.md @@ -1,3 +1,5 @@ +# `argocd proj get` Command Reference + ## argocd proj get Get project details @@ -6,6 +8,16 @@ Get project details argocd proj get PROJECT [flags] ``` +### Examples + +``` + # Get details from project PROJECT + argocd proj get PROJECT + + # Get details from project PROJECT in yaml format + argocd proj get PROJECT -o yaml +``` + ### Options ``` @@ -20,6 +32,7 @@ argocd proj get PROJECT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +45,12 @@ argocd proj get PROJECT [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_list.md b/docs/user-guide/commands/argocd_proj_list.md index a82e1bd3407e4..d96c0c4bb13b8 100644 --- a/docs/user-guide/commands/argocd_proj_list.md +++ b/docs/user-guide/commands/argocd_proj_list.md @@ -1,3 +1,5 @@ +# `argocd proj list` Command Reference + ## argocd proj list List projects @@ -6,6 +8,16 @@ List projects argocd proj list [flags] ``` +### Examples + +``` + # List all available projects + argocd proj list + + # List all available projects in yaml format + argocd proj list -o yaml +``` + ### Options ``` @@ -20,6 +32,7 @@ argocd proj list [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +45,12 @@ argocd proj list [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_remove-destination.md b/docs/user-guide/commands/argocd_proj_remove-destination.md index be4ed17477532..612e1db68356a 100644 --- a/docs/user-guide/commands/argocd_proj_remove-destination.md +++ b/docs/user-guide/commands/argocd_proj_remove-destination.md @@ -1,3 +1,5 @@ +# `argocd proj remove-destination` Command Reference + ## argocd proj remove-destination Remove project destination @@ -6,6 +8,13 @@ Remove project destination argocd proj remove-destination PROJECT SERVER NAMESPACE [flags] ``` +### Examples + +``` + # Remove the destination (SERVER) from the specified namespace (NAMESPACE) on the project with name PROJECT + argocd proj remove-destination PROJECT SERVER NAMESPACE +``` + ### Options ``` @@ -19,6 +28,7 @@ argocd proj remove-destination PROJECT SERVER NAMESPACE [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +41,12 @@ argocd proj remove-destination PROJECT SERVER NAMESPACE [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_remove-orphaned-ignore.md b/docs/user-guide/commands/argocd_proj_remove-orphaned-ignore.md index c63d59d6e0fbf..857cf3c595177 100644 --- a/docs/user-guide/commands/argocd_proj_remove-orphaned-ignore.md +++ b/docs/user-guide/commands/argocd_proj_remove-orphaned-ignore.md @@ -1,9 +1,21 @@ +# `argocd proj remove-orphaned-ignore` Command Reference + ## argocd proj remove-orphaned-ignore Remove a resource from orphaned ignore list ``` -argocd proj remove-orphaned-ignore PROJECT GROUP KIND NAME [flags] +argocd proj remove-orphaned-ignore PROJECT GROUP KIND [flags] +``` + +### Examples + +``` + # Remove a resource of the specified GROUP and KIND from orphaned ignore list on the project with name PROJECT + argocd proj remove-orphaned-ignore PROJECT GROUP KIND + + # Remove resources of the specified GROUP and KIND using a NAME pattern from orphaned ignore list on the project with name PROJECT + argocd proj remove-orphaned-ignore PROJECT GROUP KIND --name NAME ``` ### Options @@ -20,6 +32,7 @@ argocd proj remove-orphaned-ignore PROJECT GROUP KIND NAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +45,12 @@ argocd proj remove-orphaned-ignore PROJECT GROUP KIND NAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_remove-signature-key.md b/docs/user-guide/commands/argocd_proj_remove-signature-key.md index 9dfa69174fe26..61d6085022662 100644 --- a/docs/user-guide/commands/argocd_proj_remove-signature-key.md +++ b/docs/user-guide/commands/argocd_proj_remove-signature-key.md @@ -1,3 +1,5 @@ +# `argocd proj remove-signature-key` Command Reference + ## argocd proj remove-signature-key Remove GnuPG signature key from project @@ -6,6 +8,13 @@ Remove GnuPG signature key from project argocd proj remove-signature-key PROJECT KEY-ID [flags] ``` +### Examples + +``` + # Remove GnuPG signature key KEY-ID from project PROJECT + argocd proj remove-signature-key PROJECT KEY-ID +``` + ### Options ``` @@ -19,6 +28,7 @@ argocd proj remove-signature-key PROJECT KEY-ID [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +41,12 @@ argocd proj remove-signature-key PROJECT KEY-ID [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_remove-source-namespace.md b/docs/user-guide/commands/argocd_proj_remove-source-namespace.md new file mode 100644 index 0000000000000..6a0ee319c7b9b --- /dev/null +++ b/docs/user-guide/commands/argocd_proj_remove-source-namespace.md @@ -0,0 +1,55 @@ +# `argocd proj remove-source-namespace` Command Reference + +## argocd proj remove-source-namespace + +Removes the source namespace from the AppProject + +``` +argocd proj remove-source-namespace PROJECT NAMESPACE [flags] +``` + +### Examples + +``` + # Remove source NAMESPACE in PROJECT + argocd proj remove-source-namespace PROJECT NAMESPACE +``` + +### Options + +``` + -h, --help help for remove-source-namespace +``` + +### Options inherited from parent commands + +``` + --auth-token string Authentication token + --client-crt string Client certificate file + --client-crt-key string Client certificate key file + --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. + --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) + --http-retry-max int Maximum number of retries to establish http connection to Argo CD server + --insecure Skip server certificate and domain verification + --kube-context string Directs the command to the given kube-context + --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") + --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 + --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") +``` + +### SEE ALSO + +* [argocd proj](argocd_proj.md) - Manage projects + diff --git a/docs/user-guide/commands/argocd_proj_remove-source.md b/docs/user-guide/commands/argocd_proj_remove-source.md index 37b78d8b87c90..d6a1c353059f3 100644 --- a/docs/user-guide/commands/argocd_proj_remove-source.md +++ b/docs/user-guide/commands/argocd_proj_remove-source.md @@ -1,3 +1,5 @@ +# `argocd proj remove-source` Command Reference + ## argocd proj remove-source Remove project source repository @@ -6,6 +8,13 @@ Remove project source repository argocd proj remove-source PROJECT URL [flags] ``` +### Examples + +``` + # Remove URL source repository to project PROJECT + argocd proj remove-source PROJECT URL +``` + ### Options ``` @@ -19,6 +28,7 @@ argocd proj remove-source PROJECT URL [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +41,12 @@ argocd proj remove-source PROJECT URL [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_role.md b/docs/user-guide/commands/argocd_proj_role.md index a8d1ba5c2ac66..9546cc4b7ab27 100644 --- a/docs/user-guide/commands/argocd_proj_role.md +++ b/docs/user-guide/commands/argocd_proj_role.md @@ -1,3 +1,5 @@ +# `argocd proj role` Command Reference + ## argocd proj role Manage a project's roles @@ -19,6 +21,7 @@ argocd proj role [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +34,12 @@ argocd proj role [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_role_add-group.md b/docs/user-guide/commands/argocd_proj_role_add-group.md index c85bc8630fabc..4a3aa2f1e8be1 100644 --- a/docs/user-guide/commands/argocd_proj_role_add-group.md +++ b/docs/user-guide/commands/argocd_proj_role_add-group.md @@ -1,3 +1,5 @@ +# `argocd proj role add-group` Command Reference + ## argocd proj role add-group Add a group claim to a project role @@ -19,6 +21,7 @@ argocd proj role add-group PROJECT ROLE-NAME GROUP-CLAIM [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +34,12 @@ argocd proj role add-group PROJECT ROLE-NAME GROUP-CLAIM [flags] --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 + --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") ``` ### SEE ALSO 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 66c6225e0f169..d4804d31d66a1 100644 --- a/docs/user-guide/commands/argocd_proj_role_add-policy.md +++ b/docs/user-guide/commands/argocd_proj_role_add-policy.md @@ -1,3 +1,5 @@ +# `argocd proj role add-policy` Command Reference + ## argocd proj role add-policy Add a policy to a project role @@ -6,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 ``` @@ -22,6 +53,7 @@ argocd proj role add-policy PROJECT ROLE-NAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -34,8 +66,12 @@ argocd proj role add-policy PROJECT ROLE-NAME [flags] --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 + --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") ``` ### SEE ALSO 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 f71d005bbb20a..fc7eaf93c2307 100644 --- a/docs/user-guide/commands/argocd_proj_role_create-token.md +++ b/docs/user-guide/commands/argocd_proj_role_create-token.md @@ -1,3 +1,5 @@ +# `argocd proj role create-token` Command Reference + ## argocd proj role create-token Create a project token @@ -6,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 ``` @@ -22,6 +36,7 @@ argocd proj role create-token PROJECT ROLE-NAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -34,8 +49,12 @@ argocd proj role create-token PROJECT ROLE-NAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_role_create.md b/docs/user-guide/commands/argocd_proj_role_create.md index 7bf2d02b1c70b..60974c9e1b4e6 100644 --- a/docs/user-guide/commands/argocd_proj_role_create.md +++ b/docs/user-guide/commands/argocd_proj_role_create.md @@ -1,3 +1,5 @@ +# `argocd proj role create` Command Reference + ## argocd proj role create Create a project role @@ -6,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 ``` @@ -20,6 +29,7 @@ argocd proj role create PROJECT ROLE-NAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +42,12 @@ argocd proj role create PROJECT ROLE-NAME [flags] --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 + --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") ``` ### SEE ALSO 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 0d3e9efab54a5..006746f8faeeb 100644 --- a/docs/user-guide/commands/argocd_proj_role_delete-token.md +++ b/docs/user-guide/commands/argocd_proj_role_delete-token.md @@ -1,3 +1,5 @@ +# `argocd proj role delete-token` Command Reference + ## argocd proj role delete-token Delete a project token @@ -6,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 ``` @@ -19,6 +53,7 @@ argocd proj role delete-token PROJECT ROLE-NAME ISSUED-AT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +66,12 @@ argocd proj role delete-token PROJECT ROLE-NAME ISSUED-AT [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_role_delete.md b/docs/user-guide/commands/argocd_proj_role_delete.md index 29a966d0a3842..fe94a2231db60 100644 --- a/docs/user-guide/commands/argocd_proj_role_delete.md +++ b/docs/user-guide/commands/argocd_proj_role_delete.md @@ -1,3 +1,5 @@ +# `argocd proj role delete` Command Reference + ## argocd proj role delete Delete a project role @@ -6,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 ``` @@ -19,6 +27,7 @@ argocd proj role delete PROJECT ROLE-NAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +40,12 @@ argocd proj role delete PROJECT ROLE-NAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_role_get.md b/docs/user-guide/commands/argocd_proj_role_get.md index a610b62af2f1d..e21276ce85116 100644 --- a/docs/user-guide/commands/argocd_proj_role_get.md +++ b/docs/user-guide/commands/argocd_proj_role_get.md @@ -1,3 +1,5 @@ +# `argocd proj role get` Command Reference + ## argocd proj role get Get the details of a specific role @@ -6,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 ``` @@ -19,6 +36,7 @@ argocd proj role get PROJECT ROLE-NAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +49,12 @@ argocd proj role get PROJECT ROLE-NAME [flags] --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 + --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") ``` ### SEE ALSO 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 e5bfdb941935b..8d1fe93163dfc 100644 --- a/docs/user-guide/commands/argocd_proj_role_list-tokens.md +++ b/docs/user-guide/commands/argocd_proj_role_list-tokens.md @@ -1,3 +1,5 @@ +# `argocd proj role list-tokens` Command Reference + ## argocd proj role list-tokens List tokens for a given role. @@ -6,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 ``` @@ -20,6 +32,7 @@ argocd proj role list-tokens PROJECT ROLE-NAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +45,12 @@ argocd proj role list-tokens PROJECT ROLE-NAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_role_list.md b/docs/user-guide/commands/argocd_proj_role_list.md index 3e2928b2ea7de..3cfd630ddc988 100644 --- a/docs/user-guide/commands/argocd_proj_role_list.md +++ b/docs/user-guide/commands/argocd_proj_role_list.md @@ -1,3 +1,5 @@ +# `argocd proj role list` Command Reference + ## argocd proj role list List all the roles in a project @@ -6,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 ``` @@ -20,6 +32,7 @@ argocd proj role list PROJECT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +45,12 @@ argocd proj role list PROJECT [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_role_remove-group.md b/docs/user-guide/commands/argocd_proj_role_remove-group.md index 6ca5c8a9f4283..a89e0bcfae315 100644 --- a/docs/user-guide/commands/argocd_proj_role_remove-group.md +++ b/docs/user-guide/commands/argocd_proj_role_remove-group.md @@ -1,3 +1,5 @@ +# `argocd proj role remove-group` Command Reference + ## argocd proj role remove-group Remove a group claim from a role within a project @@ -19,6 +21,7 @@ argocd proj role remove-group PROJECT ROLE-NAME GROUP-CLAIM [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +34,12 @@ argocd proj role remove-group PROJECT ROLE-NAME GROUP-CLAIM [flags] --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 + --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") ``` ### SEE ALSO 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 a7d68cbd30c64..96aee05da86eb 100644 --- a/docs/user-guide/commands/argocd_proj_role_remove-policy.md +++ b/docs/user-guide/commands/argocd_proj_role_remove-policy.md @@ -1,3 +1,5 @@ +# `argocd proj role remove-policy` Command Reference + ## argocd proj role remove-policy Remove a policy from a role within a project @@ -6,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 ``` @@ -22,6 +53,7 @@ argocd proj role remove-policy PROJECT ROLE-NAME [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -34,8 +66,12 @@ argocd proj role remove-policy PROJECT ROLE-NAME [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_set.md b/docs/user-guide/commands/argocd_proj_set.md index 04a87ae2bcf14..3dc0cc06ec787 100644 --- a/docs/user-guide/commands/argocd_proj_set.md +++ b/docs/user-guide/commands/argocd_proj_set.md @@ -1,3 +1,5 @@ +# `argocd proj set` Command Reference + ## argocd proj set Set project parameters @@ -6,6 +8,16 @@ Set project parameters argocd proj set PROJECT [flags] ``` +### Examples + +``` + # Set project parameters with some allowed cluster resources [RES1,RES2,...] for project with name PROJECT + argocd proj set PROJECT --allow-cluster-resource [RES1,RES2,...] + + # Set project parameters with some denied namespaced resources [RES1,RES2,...] for project with name PROJECT + argocd proj set PROJECT ---deny-namespaced-resource [RES1,RES2,...] +``` + ### Options ``` @@ -30,6 +42,7 @@ argocd proj set PROJECT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -42,8 +55,12 @@ argocd proj set PROJECT [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_windows.md b/docs/user-guide/commands/argocd_proj_windows.md index 5dac140a6861c..0b22c2098dc82 100644 --- a/docs/user-guide/commands/argocd_proj_windows.md +++ b/docs/user-guide/commands/argocd_proj_windows.md @@ -1,3 +1,5 @@ +# `argocd proj windows` Command Reference + ## argocd proj windows Manage a project's sync windows @@ -6,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 ``` @@ -19,6 +38,7 @@ argocd proj windows [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +51,12 @@ argocd proj windows [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_windows_add.md b/docs/user-guide/commands/argocd_proj_windows_add.md index de49ef307ab90..52fd3a8354ee3 100644 --- a/docs/user-guide/commands/argocd_proj_windows_add.md +++ b/docs/user-guide/commands/argocd_proj_windows_add.md @@ -1,3 +1,5 @@ +# `argocd proj windows add` Command Reference + ## argocd proj windows add Add a sync window to a project @@ -6,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 ``` @@ -27,6 +52,7 @@ argocd proj windows add PROJECT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -39,8 +65,12 @@ argocd proj windows add PROJECT [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_windows_delete.md b/docs/user-guide/commands/argocd_proj_windows_delete.md index 2f35f70263b82..6faf7dbeedc19 100644 --- a/docs/user-guide/commands/argocd_proj_windows_delete.md +++ b/docs/user-guide/commands/argocd_proj_windows_delete.md @@ -1,3 +1,5 @@ +# `argocd proj windows delete` Command Reference + ## argocd proj windows delete Delete a sync window from a project. Requires ID which can be found by running "argocd proj windows list PROJECT" @@ -6,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 ``` @@ -19,6 +32,7 @@ argocd proj windows delete PROJECT ID [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +45,12 @@ argocd proj windows delete PROJECT ID [flags] --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 + --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") ``` ### SEE ALSO 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 4c3a6e6465318..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 @@ -1,3 +1,5 @@ +# `argocd proj windows disable-manual-sync` Command Reference + ## argocd proj windows disable-manual-sync Disable manual sync for a sync window @@ -10,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 ``` @@ -23,6 +36,7 @@ argocd proj windows disable-manual-sync PROJECT ID [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -35,8 +49,12 @@ argocd proj windows disable-manual-sync PROJECT ID [flags] --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 + --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") ``` ### SEE ALSO 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 0ce894322bf1d..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 @@ -1,3 +1,5 @@ +# `argocd proj windows enable-manual-sync` Command Reference + ## argocd proj windows enable-manual-sync Enable manual sync for a sync window @@ -10,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 ``` @@ -23,6 +39,7 @@ argocd proj windows enable-manual-sync PROJECT ID [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -35,8 +52,12 @@ argocd proj windows enable-manual-sync PROJECT ID [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_windows_list.md b/docs/user-guide/commands/argocd_proj_windows_list.md index 725104f2153f3..3c361f90d2a68 100644 --- a/docs/user-guide/commands/argocd_proj_windows_list.md +++ b/docs/user-guide/commands/argocd_proj_windows_list.md @@ -1,3 +1,5 @@ +# `argocd proj windows list` Command Reference + ## argocd proj windows list List project sync windows @@ -6,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 ``` @@ -20,6 +36,7 @@ argocd proj windows list PROJECT [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +49,12 @@ argocd proj windows list PROJECT [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_proj_windows_update.md b/docs/user-guide/commands/argocd_proj_windows_update.md index 0916042b62bf6..e01e3787d51a2 100644 --- a/docs/user-guide/commands/argocd_proj_windows_update.md +++ b/docs/user-guide/commands/argocd_proj_windows_update.md @@ -1,3 +1,5 @@ +# `argocd proj windows update` Command Reference + ## argocd proj windows update Update a project sync window @@ -10,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 ``` @@ -29,6 +40,7 @@ argocd proj windows update PROJECT ID [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -41,8 +53,12 @@ argocd proj windows update PROJECT ID [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_relogin.md b/docs/user-guide/commands/argocd_relogin.md index 93d848d46b45c..430ab4a9222c9 100644 --- a/docs/user-guide/commands/argocd_relogin.md +++ b/docs/user-guide/commands/argocd_relogin.md @@ -1,3 +1,5 @@ +# `argocd relogin` Command Reference + ## argocd relogin Refresh an expired authenticate token @@ -10,12 +12,29 @@ Refresh an expired authenticate token argocd relogin [flags] ``` +### Examples + +``` + +# Reinitiates the login with previous contexts +argocd relogin + +# Reinitiates the login with password +argocd relogin --password YOUR_PASSWORD + +# Configure direct access using Kubernetes API server +argocd login cd.argoproj.io --core + +# If user logged in with - "argocd login cd.argoproj.io" with sso login +# The command - "argocd relogin" will Reinitiates SSO login and updates the server context +``` + ### Options ``` -h, --help help for relogin - --password string the password of an account to authenticate - --sso-port int port to run local OAuth2 login application (default 8085) + --password string The password of an account to authenticate + --sso-port int Port to run local OAuth2 login application (default 8085) ``` ### Options inherited from parent commands @@ -25,6 +44,7 @@ argocd relogin [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -37,8 +57,12 @@ argocd relogin [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_repo.md b/docs/user-guide/commands/argocd_repo.md index e6e91d8ae8754..4df85f7b00d3d 100644 --- a/docs/user-guide/commands/argocd_repo.md +++ b/docs/user-guide/commands/argocd_repo.md @@ -1,3 +1,5 @@ +# `argocd repo` Command Reference + ## argocd repo Manage repository connection parameters @@ -6,6 +8,24 @@ Manage repository connection parameters argocd repo [flags] ``` +### Examples + +``` + +# Add git repository connection parameters +argocd repo add git@git.example.com:repos/repo + +# Get a Configured Repository by URL +argocd repo get https://github.com/yourusername/your-repo.git + +# List Configured Repositories +argocd repo list + +# Remove Repository Credentials +argocd repo rm https://github.com/yourusername/your-repo.git + +``` + ### Options ``` @@ -17,6 +37,7 @@ argocd repo [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 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 @@ -37,6 +58,7 @@ argocd repo [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -49,8 +71,12 @@ argocd repo [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_repo_add.md b/docs/user-guide/commands/argocd_repo_add.md index e6d64d6c06739..8399d48302509 100644 --- a/docs/user-guide/commands/argocd_repo_add.md +++ b/docs/user-guide/commands/argocd_repo_add.md @@ -1,3 +1,5 @@ +# `argocd repo add` Command Reference + ## argocd repo add Add git repository connection parameters @@ -15,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 @@ -46,6 +54,7 @@ argocd repo add REPOURL [flags] ``` --enable-lfs enable git-lfs (Large File Support) on this repository --enable-oci enable helm-oci (Helm OCI-Based Repository) + --force-http-basic-auth whether to force use of basic auth when connecting repository via HTTP --gcp-service-account-key-path string service account key for the Google Cloud Platform --github-app-enterprise-base-url string base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3 --github-app-id int id of the GitHub Application @@ -73,6 +82,7 @@ argocd repo add REPOURL [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -85,8 +95,12 @@ argocd repo add REPOURL [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_repo_get.md b/docs/user-guide/commands/argocd_repo_get.md index bbe298be7d36d..5a900adb09487 100644 --- a/docs/user-guide/commands/argocd_repo_get.md +++ b/docs/user-guide/commands/argocd_repo_get.md @@ -1,3 +1,5 @@ +# `argocd repo get` Command Reference + ## argocd repo get Get a configured repository by URL @@ -11,7 +13,7 @@ argocd repo get [flags] ``` -h, --help help for get -o, --output string Output format. One of: json|yaml|wide|url (default "wide") - --refresh string Force a cache refresh on connection status + --refresh string Force a cache refresh on connection status , must be one of: 'hard' ``` ### Options inherited from parent commands @@ -21,6 +23,7 @@ argocd repo get [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -33,8 +36,12 @@ argocd repo get [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_repo_list.md b/docs/user-guide/commands/argocd_repo_list.md index 488bda33584ed..06f1f788cb7c2 100644 --- a/docs/user-guide/commands/argocd_repo_list.md +++ b/docs/user-guide/commands/argocd_repo_list.md @@ -1,3 +1,5 @@ +# `argocd repo list` Command Reference + ## argocd repo list List configured repositories @@ -11,7 +13,7 @@ argocd repo list [flags] ``` -h, --help help for list -o, --output string Output format. One of: json|yaml|wide|url (default "wide") - --refresh string Force a cache refresh on connection status + --refresh string Force a cache refresh on connection status , must be one of: 'hard' ``` ### Options inherited from parent commands @@ -21,6 +23,7 @@ argocd repo list [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -33,8 +36,12 @@ argocd repo list [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_repo_rm.md b/docs/user-guide/commands/argocd_repo_rm.md index c33ef807bb82e..01e89d48e76a1 100644 --- a/docs/user-guide/commands/argocd_repo_rm.md +++ b/docs/user-guide/commands/argocd_repo_rm.md @@ -1,3 +1,5 @@ +# `argocd repo rm` Command Reference + ## argocd repo rm Remove repository credentials @@ -19,6 +21,7 @@ argocd repo rm REPO [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +34,12 @@ argocd repo rm REPO [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_repocreds.md b/docs/user-guide/commands/argocd_repocreds.md index f2a52f42fbb92..f073b2bbb6161 100644 --- a/docs/user-guide/commands/argocd_repocreds.md +++ b/docs/user-guide/commands/argocd_repocreds.md @@ -1,3 +1,5 @@ +# `argocd repocreds` Command Reference + ## argocd repocreds Manage repository connection parameters @@ -6,6 +8,19 @@ Manage repository connection parameters argocd repocreds [flags] ``` +### Examples + +``` + # Add credentials with user/pass authentication to use for all repositories under the specified URL + argocd repocreds add URL --username USERNAME --password PASSWORD + + # List all the configured repository credentials + argocd repocreds list + + # Remove credentials for the repositories with speficied URL + argocd repocreds rm URL +``` + ### Options ``` @@ -17,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 @@ -37,6 +53,7 @@ argocd repocreds [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -49,8 +66,12 @@ argocd repocreds [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_repocreds_add.md b/docs/user-guide/commands/argocd_repocreds_add.md index 42e30d65e0618..ce66dc49cfe8c 100644 --- a/docs/user-guide/commands/argocd_repocreds_add.md +++ b/docs/user-guide/commands/argocd_repocreds_add.md @@ -1,3 +1,5 @@ +# `argocd repocreds add` Command Reference + ## argocd repocreds add Add git repository connection parameters @@ -33,6 +35,7 @@ argocd repocreds add REPOURL [flags] ``` --enable-oci Specifies whether helm-oci support should be enabled for this repo + --force-http-basic-auth whether to force basic auth when connecting via HTTP --gcp-service-account-key-path string service account key for the Google Cloud Platform --github-app-enterprise-base-url string base url to use when using GitHub Enterprise (e.g. https://ghe.example.com/api/v3 --github-app-id int id of the GitHub Application @@ -55,6 +58,7 @@ argocd repocreds add REPOURL [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -67,8 +71,12 @@ argocd repocreds add REPOURL [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_repocreds_list.md b/docs/user-guide/commands/argocd_repocreds_list.md index f0d7a6bcae570..ae358afab2056 100644 --- a/docs/user-guide/commands/argocd_repocreds_list.md +++ b/docs/user-guide/commands/argocd_repocreds_list.md @@ -1,3 +1,5 @@ +# `argocd repocreds list` Command Reference + ## argocd repocreds list List configured repository credentials @@ -6,6 +8,22 @@ List configured repository credentials argocd repocreds list [flags] ``` +### Examples + +``` + # List all repo urls + argocd repocreds list + + # 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 ``` @@ -20,6 +38,7 @@ argocd repocreds list [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -32,8 +51,12 @@ argocd repocreds list [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_repocreds_rm.md b/docs/user-guide/commands/argocd_repocreds_rm.md index 678e70afd50c1..3bfee30eb40a3 100644 --- a/docs/user-guide/commands/argocd_repocreds_rm.md +++ b/docs/user-guide/commands/argocd_repocreds_rm.md @@ -1,3 +1,5 @@ +# `argocd repocreds rm` Command Reference + ## argocd repocreds rm Remove repository credentials @@ -6,6 +8,13 @@ Remove repository credentials argocd repocreds rm CREDSURL [flags] ``` +### Examples + +``` + # Remove credentials for the repositories with URL https://git.example.com/repos + argocd repocreds rm https://git.example.com/repos/ +``` + ### Options ``` @@ -19,6 +28,7 @@ argocd repocreds rm CREDSURL [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -31,8 +41,12 @@ argocd repocreds rm CREDSURL [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_version.md b/docs/user-guide/commands/argocd_version.md index a8ecfa69ea0f1..6a7fa7baf5ecb 100644 --- a/docs/user-guide/commands/argocd_version.md +++ b/docs/user-guide/commands/argocd_version.md @@ -1,3 +1,5 @@ +# `argocd version` Command Reference + ## argocd version Print version information @@ -35,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 @@ -57,6 +60,7 @@ argocd version [flags] --client-crt string Client certificate file --client-crt-key string Client certificate key file --config string Path to Argo CD config (default "/home/user/.config/argocd/config") + --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. --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. @@ -69,8 +73,12 @@ argocd version [flags] --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 + --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") ``` ### SEE ALSO diff --git a/docs/user-guide/config-management-plugins.md b/docs/user-guide/config-management-plugins.md new file mode 100644 index 0000000000000..652f545d7c4c1 --- /dev/null +++ b/docs/user-guide/config-management-plugins.md @@ -0,0 +1,3 @@ +# Config Management Plugins + +This page has been moved to the [operator manual](../operator-manual/config-management-plugins.md). 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 ed8bf4d054909..61f799e514d6a 100644 --- a/docs/user-guide/diffing.md +++ b/docs/user-guide/diffing.md @@ -60,14 +60,23 @@ To ignore fields owned by specific managers defined in your live resources: ```yaml spec: ignoreDifferences: - - group: * - kind: * + - group: "*" + kind: "*" managedFieldsManagers: - kube-controller-manager ``` The above configuration will ignore differences from all fields owned by `kube-controller-manager` for all resources belonging to this application. +If you have a slash `/` in your pointer path, you can use the `~1` character. For example: + +```yaml +spec: + ignoreDifferences: + - kind: Node + jsonPointers: /metadata/labels/node-role.kubernetes.io~1worker +``` + ## System-Level Configuration The comparison of resources with well-known issues can be customized at a system level. Ignored differences can be configured for a specified group and kind @@ -172,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/directory.md b/docs/user-guide/directory.md index 278911b013410..f422f7311cfd3 100644 --- a/docs/user-guide/directory.md +++ b/docs/user-guide/directory.md @@ -43,6 +43,9 @@ spec: recurse: true ``` +!!! warning + Directory-type applications only work for plain manifest files. If Argo CD encounters Kustomize, Helm, or Jsonnet files when directory: is set, it will fail to render the manifests. + ## Including/Excluding Files ### Including Only Certain Files diff --git a/docs/user-guide/environment-variables.md b/docs/user-guide/environment-variables.md index ceea5798e83a3..cff6446617fa3 100644 --- a/docs/user-guide/environment-variables.md +++ b/docs/user-guide/environment-variables.md @@ -2,8 +2,14 @@ The following environment variables can be used with `argocd` CLI: -| Environment Variable | Description | -| --- | --- | -| `ARGOCD_SERVER` | the address of the ArgoCD 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_AUTH_TOKEN` | the ArgoCD `apiKey` for your ArgoCD user to be able to authenticate | -| `ARGOCD_OPTS` | command-line options to pass to `argocd` CLI
    eg. `ARGOCD_OPTS="--grpc-web"` | +| 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.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") | +| `ARGOCD_REPO_SERVER_NAME` | the Argo CD Repository Server name (default "argocd-repo-server") | +| `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 173a8724c5fea..7f08ea6c80bf4 100644 --- a/docs/user-guide/external-url.md +++ b/docs/user-guide/external-url.md @@ -1,6 +1,6 @@ # Add external URL -You can add additional external links to ArgoCD dashboard. For example +You can add additional external links to Argo CD dashboard. For example links monitoring pages or documentation instead of just ingress hosts or other apps. ArgoCD generates a clickable links to external pages for a resource based on per resource annotation. @@ -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/extra_info.md b/docs/user-guide/extra_info.md new file mode 100644 index 0000000000000..298b457a81bd4 --- /dev/null +++ b/docs/user-guide/extra_info.md @@ -0,0 +1,28 @@ +# Add extra Application info + +You can add additional information to an Application on your Argo CD dashboard. +If you wish to add clickable links, see [Add external URL](https://argo-cd.readthedocs.io/en/stable/user-guide/external-url/). + +This is done by providing the 'info' field a key-value in your Application manifest. + +Example: +```yaml +project: argo-demo +source: + repoURL: 'https://demo' + path: argo-demo +destination: + server: https://demo + namespace: argo-demo +info: + - name: Example: + value: >- + https://example.com +``` +![External link](../assets/extra_info-1.png) + +The additional information will be visible on the Argo CD Application details page. + +![External link](../assets/extra_info.png) + +![External link](../assets/extra_info-2.png) diff --git a/docs/user-guide/helm.md b/docs/user-guide/helm.md index b75cebc43078f..7a763336abcc8 100644 --- a/docs/user-guide/helm.md +++ b/docs/user-guide/helm.md @@ -2,7 +2,9 @@ ## Declarative -You can install Helm charts through the UI, or in the declarative GitOps way. Here is an example: +You can install Helm charts through the UI, or in the declarative GitOps way. +Helm is [only used to inflate charts with `helm template`](../../faq#after-deploying-my-helm-application-with-argo-cd-i-cannot-see-it-with-helm-ls-and-other-helm-commands). The lifecycle of the application is handled by Argo CD instead of Helm. +Here is an example: ```yaml apiVersion: argoproj.io/v1alpha1 @@ -23,6 +25,28 @@ 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) + +See [here](../operator-manual/declarative-setup.md#helm-chart-repositories) for more info about how to configure private Helm repositories. + ## Values Files Helm has the ability to use a different, or even multiple "values.yaml" files to derive its @@ -33,9 +57,11 @@ flag. The flag can be repeated to support multiple values files: argocd app set helm-guestbook --values values-production.yaml ``` !!! note - Values files must be in the same git repository as the Helm chart. The files can be in a different - location in which case it can be accessed using a relative path relative to the root directory of - the Helm chart. + Before `v2.6` of Argo CD, Values files must be in the same git repository as the Helm + chart. The files can be in a different location in which case it can be accessed using + a relative path relative to the root directory of the Helm chart. + As of `v2.6`, values files can be sourced from a separate repository than the Helm chart + by taking advantage of [multiple sources for Applications](./multiple_sources.md#helm-value-files-from-external-git-repository). In the declarative syntax: @@ -46,6 +72,50 @@ source: - values-production.yaml ``` +## Values + +Argo CD supports the equivalent of a values file directly in the Application manifest using the `source.helm.valuesObject` key. + +```yaml +source: + helm: + valuesObject: + ingress: + enabled: true + path: / + hosts: + - mydomain.example.com + annotations: + kubernetes.io/ingress.class: nginx + kubernetes.io/tls-acme: "true" + labels: {} + tls: + - secretName: mydomain-tls + hosts: + - mydomain.example.com +``` + +Alternatively, values can be passed in as a string using the `source.helm.values` key. + +```yaml +source: + helm: + values: | + ingress: + enabled: true + path: / + hosts: + - mydomain.example.com + annotations: + kubernetes.io/ingress.class: nginx + kubernetes.io/tls-acme: "true" + labels: {} + tls: + - secretName: mydomain-tls + hosts: + - mydomain.example.com +``` + ## Helm Parameters Helm has the ability to set parameter values, which override any values in @@ -72,9 +142,68 @@ source: value: LoadBalancer ``` +## Helm Value Precedence +Values injections have the following order of precedence + `parameters > valuesObject > values > valueFiles > helm repository values.yaml` + Or rather + +``` + lowest -> valueFiles + -> values + -> valuesObject + highest -> parameters +``` + +so values/valuesObject trumps valueFiles, and parameters trump both. + +Precedence of valueFiles themselves is the order they are defined in + +``` +if we have + +valuesFile: + - values-file-2.yaml + - values-file-1.yaml + +the last values-file i.e. values-file-1.yaml will trump the first +``` + +When multiple of the same key are found the last one wins i.e + +``` +e.g. if we only have values-file-1.yaml and it contains + +param1: value1 +param1: value3000 + +we get param1=value3000 +``` + +``` +parameters: + - name: "param1" + value: value2 + - name: "param1" + value: value1 + +the result will be param1=value1 +``` + +``` +values: | + param1: value2 + param1: value5 + +the result will be param1=value5 +``` + +!!! note "When valuesFiles or values is used" + The list of parameters seen in the ui is not what is used for resources, rather it is the values/valuesObject merged with parameters (see [this issue](https://github.com/argoproj/argo-cd/issues/9213) incase it has been resolved) + As a workaround using parameters instead of values/valuesObject will provide a better overview of what will be used for resources + ## Helm Release Name -By default, the Helm release name is equal to the Application name to which it belongs. Sometimes, especially on a centralised ArgoCD, +By default, the Helm release name is equal to the Application name to which it belongs. Sometimes, especially on a centralised Argo CD, you may want to override that name, and it is possible with the `release-name` flag on the cli: ```bash @@ -90,7 +219,7 @@ source: ``` !!! warning "Important notice on overriding the release name" - Please note that overriding the Helm release name might cause problems when the chart you are deploying is using the `app.kubernetes.io/instance` label. ArgoCD injects this label with the value of the Application name for tracking purposes. So when overriding the release name, the Application name will stop being equal to the release name. Because ArgoCD will overwrite the label with the Application name it might cause some selectors on the resources to stop working. In order to avoid this we can configure ArgoCD to use another label for tracking in the [ArgoCD configmap argocd-cm.yaml](../operator-manual/argocd-cm.yaml) - check the lines describing `application.instanceLabelKey`. + Please note that overriding the Helm release name might cause problems when the chart you are deploying is using the `app.kubernetes.io/instance` label. Argo CD injects this label with the value of the Application name for tracking purposes. So when overriding the release name, the Application name will stop being equal to the release name. Because Argo CD will overwrite the label with the Application name it might cause some selectors on the resources to stop working. In order to avoid this we can configure Argo CD to use another label for tracking in the [ArgoCD configmap argocd-cm.yaml](../operator-manual/argocd-cm.yaml) - check the lines describing `application.instanceLabelKey`. ## Helm Hooks @@ -99,25 +228,29 @@ 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. | -| `helm.sh/hook: pre-install` | Supported as equivalent to `argocd.argoproj.io/hook: PreSync`. | -| `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-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. | -| `helm.sh/hook-delete-policy` | Supported. See also `argocd.argoproj.io/hook-delete-policy`). | -| `helm.sh/hook-delete-timeout` | No supported. Never used in Helm stable | -| `helm.sh/hook-weight` | Supported as equivalent to `argocd.argoproj.io/sync-wave`. | +| 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. | +| `helm.sh/hook: pre-install` | Supported as equivalent to `argocd.argoproj.io/hook: PreSync`. | +| `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` | 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. | +| `helm.sh/hook-delete-policy` | Supported. See also `argocd.argoproj.io/hook-delete-policy`). | +| `helm.sh/hook-delete-timeout` | Not supported. Never used in Helm stable | +| `helm.sh/hook-weight` | Supported as equivalent to `argocd.argoproj.io/sync-wave`. | +| `helm.sh/resource-policy: keep` | Supported as equivalent to `argocd.argoproj.io/sync-options: Delete=false`. | Unsupported hooks are ignored. In Argo CD, hooks are created by using `kubectl apply`, rather than `kubectl create`. This means that if the hook is named and already exists, it will not change unless you have annotated it with `before-hook-creation`. +!!! warning "Helm hooks + ArgoCD hooks" + If you define any Argo CD hooks, _all_ Helm hooks will be ignored. + !!! warning "'install' vs 'upgrade' vs 'sync'" Argo CD cannot know if it is running a first-time "install" or an "upgrade" - every operation is a "sync'. This means that, by default, apps that have `pre-install` and `pre-upgrade` will have those hooks run at the same time. @@ -202,7 +335,7 @@ One way to use this plugin is to prepare your own ArgoCD image where it is inclu Example `Dockerfile`: -``` +```dockerfile FROM argoproj/argocd:v1.5.7 USER root @@ -232,38 +365,43 @@ Some users find this pattern preferable to maintaining their own version of the Below is an example of how to add Helm plugins when installing ArgoCD with the [official ArgoCD helm chart](https://github.com/argoproj/argo-helm/tree/master/charts/argo-cd): -``` +```yaml repoServer: volumes: - - name: gcloud + - name: gcp-credentials secret: - secretName: helm-credentials + secretName: my-gcp-credentials volumeMounts: - - mountPath: /gcloud - name: gcloud + - name: gcp-credentials + mountPath: /gcp env: - - name: HELM_PLUGINS - value: /helm-working-dir/plugins/ - - name: GOOGLE_APPLICATION_CREDENTIALS - value: /gcloud/key.json + - name: HELM_CACHE_HOME + value: /helm-working-dir + - name: HELM_CONFIG_HOME + value: /helm-working-dir + - name: HELM_DATA_HOME + value: /helm-working-dir initContainers: - - name: install-helm-plugins - image: alpine/helm:3.8.0 + - name: helm-gcp-authentication + image: alpine/helm:3.8.1 volumeMounts: - - mountPath: /helm-working-dir - name: helm-working-dir - - mountPath: /gcloud - name: gcloud + - name: helm-working-dir + mountPath: /helm-working-dir + - name: gcp-credentials + mountPath: /gcp env: - - name: GOOGLE_APPLICATION_CREDENTIALS - value: /gcloud/key.json - - name: HELM_PLUGINS - value: /helm-working-dir/plugins - command: ["/bin/sh", "-c"] + - name: HELM_CACHE_HOME + value: /helm-working-dir + - name: HELM_CONFIG_HOME + value: /helm-working-dir + - name: HELM_DATA_HOME + value: /helm-working-dir + command: [ "/bin/sh", "-c" ] args: - apk --no-cache add curl; helm plugin install https://github.com/hayorov/helm-gcs.git; - helm repo add my-private-gcs-repo gs://my-private-gcs-repo; + helm repo add my-gcs-repo gs://my-private-helm-gcs-repository; + chmod -R 777 $HELM_DATA_HOME; ``` ## Helm Version @@ -291,7 +429,7 @@ Helm, [starting with v3.6.1](https://github.com/helm/helm/releases/tag/v3.6.1), prevents sending repository credentials to download charts that are being served from a different domain than the repository. -If needed, it is possible to specifically set the Helm version to template with by setting the `helm-pass-credentials` flag on the cli: +If needed, it is possible to opt into passing credentials for all domains by setting the `helm-pass-credentials` flag on the cli: ```bash argocd app set helm-guestbook --helm-pass-credentials diff --git a/docs/user-guide/jsonnet.md b/docs/user-guide/jsonnet.md index 699cd45335b61..194daa06c2591 100644 --- a/docs/user-guide/jsonnet.md +++ b/docs/user-guide/jsonnet.md @@ -1,6 +1,6 @@ # Jsonnet -Any file matching `*.jsonnet` in a directory app is treated as a Jsonnet file. ArgoCD evaluates the Jsonnet and is able to parse a generated object or array. +Any file matching `*.jsonnet` in a directory app is treated as a Jsonnet file. Argo CD evaluates the Jsonnet and is able to parse a generated object or array. ## Build Environment diff --git a/docs/user-guide/kustomize.md b/docs/user-guide/kustomize.md index b940cc9a154e1..1aa876fb74224 100644 --- a/docs/user-guide/kustomize.md +++ b/docs/user-guide/kustomize.md @@ -5,14 +5,139 @@ The following configuration options are available for Kustomize: * `namePrefix` is a prefix appended to resources for Kustomize apps * `nameSuffix` is a suffix appended to resources for Kustomize apps * `images` is a list of Kustomize image overrides +* `replicas` is a list of Kustomize replica overrides * `commonLabels` is a string map of additional labels +* `labelWithoutSelector` is a boolean value which defines if the common label(s) should be applied to resource selectors and templates. +* `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 +* `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. !!! tip 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. `patches` follow the same logic as the corresponding Kustomization. Any patches that target existing Kustomization file will be merged. + +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 +metadata: + name: kustomize-inline-example +namespace: test1 +resources: + - https://github.com/argoproj/argocd-example-apps//kustomize-guestbook/ +patches: + - target: + kind: Deployment + name: guestbook-ui + patch: |- + - op: replace + path: /spec/template/spec/containers/0/ports/0/containerPort + value: 443 +``` + +This `Application` does the equivalent using the inline `kustomize.patches` configuration. +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: kustomize-inline-guestbook + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + destination: + namespace: test1 + server: https://kubernetes.default.svc + project: default + source: + path: kustomize-guestbook + repoURL: https://github.com/argoproj/argocd-example-apps.git + targetRevision: master + kustomize: + patches: + - target: + kind: Deployment + name: guestbook-ui + patch: |- + - op: replace + path: /spec/template/spec/containers/0/ports/0/containerPort + 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. @@ -38,6 +163,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. @@ -86,6 +214,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). @@ -104,3 +260,10 @@ data: kustomize.buildOptions: --enable-helm ``` +## Setting the manifests' namespace + +The `spec.destination.namespace` field only adds a namespace when it's missing from the manifests generated by Kustomize. It also uses `kubectl` to set the namespace, which sometimes misses namespace fields in certain resources (for example, custom resources). In these cases, you might get an error like this: `ClusterRoleBinding.rbac.authorization.k8s.io "example" is invalid: subjects[0].namespace: Required value.` + +Using Kustomize directly to set the missing namespaces can resolve this problem. Setting `spec.source.kustomize.namespace` instructs Kustomize to set namespace fields to the given value. + +If `spec.destination.namespace` and `spec.source.kustomize.namespace` are both set, Argo CD will defer to the latter, the namespace value set by Kustomize. diff --git a/docs/user-guide/multiple_sources.md b/docs/user-guide/multiple_sources.md index 5aef3825389f7..e539f8f6288aa 100644 --- a/docs/user-guide/multiple_sources.md +++ b/docs/user-guide/multiple_sources.md @@ -36,6 +36,9 @@ spec: The above example has two sources specified. Argo CD will generate the manifests for each source separately and combine the resulting manifests. +!!! warning "Do not abuse multiple sources" + Note that the example above is just for illustration purposes. This feature is **NOT** destined as a generic way to group your applications. Take a look at [applicationsets](../user-guide/application-set.md) and the [app-of-apps](../../operator-manual/cluster-bootstrapping/) pattern if you want to have a single entity for multiple applications. If you find yourself using more than 2-3 items in the `sources` array then you are almost certainly abusing this feature and you need to rethink your application grouping strategy. + If multiple sources produce the same resource (same `group`, `kind`, `name`, and `namespace`), the last source to produce the resource will take precedence. Argo CD will produce a `RepeatedResourceWarning` in this case, but it will sync the resources. This provides a convenient way to override a resource from a chart with a resource from a Git repo. @@ -56,7 +59,7 @@ spec: helm: valueFiles: - $values/charts/prometheus/values.yaml - - repoURL: 'https://git.example.gom/org/value-files.git' + - repoURL: 'https://git.example.com/org/value-files.git' targetRevision: dev ref: values ``` @@ -71,3 +74,6 @@ at that URL. If the `path` field is not set, Argo CD will use the repository sol !!! note Sources with the `ref` field set must not also specify the `chart` field. Argo CD does not currently support using another Helm chart as a source for value files. + +!!! note + Even when the `ref` field is configured with the `path` field, `$value` still represents the root of sources with the `ref` field. Consequently, `valueFiles` must be specified as relative paths from the root of sources. diff --git a/docs/user-guide/private-repositories.md b/docs/user-guide/private-repositories.md index 04fedaea4f99d..074e5caad9e96 100644 --- a/docs/user-guide/private-repositories.md +++ b/docs/user-guide/private-repositories.md @@ -3,7 +3,7 @@ !!!note Some Git hosters - notably GitLab and possibly on-premise GitLab instances as well - require you to specify the `.git` suffix in the repository URL, otherwise they will send a HTTP 301 redirect to the - repository URL suffixed with `.git`. ArgoCD will **not** follow these redirects, so you have to + repository URL suffixed with `.git`. Argo CD will **not** follow these redirects, so you have to adapt your repository URL to be suffixed with `.git`. ## Credentials @@ -26,13 +26,13 @@ or UI: ![connect repo overview](../assets/repo-add-overview.png) -1. Click `Connect Repo using HTTPS` button and enter credentials +2. Click `Connect Repo using HTTPS` button and enter credentials ![connect repo](../assets/repo-add-https.png) *Note: username in screenshot is for illustration purposes only , we have no relationship to this GitHub account should it exist.* -1. Click `Connect` to test the connection and have the repository added +3. Click `Connect` to test the connection and have the repository added ![connect repo](../assets/connect-repo.png) @@ -52,7 +52,7 @@ Then, connect the repository using any non-empty string as username and the acce ### TLS Client Certificates for HTTPS repositories -If your repository server requires you to use TLS client certificates for authentication, you can configure ArgoCD repositories to make use of them. For this purpose, `--tls-client-cert-path` and `--tls-client-cert-key-path` switches to the `argocd repo add` command can be used to specify the files on your local system containing client certificate and the corresponding key, respectively: +If your repository server requires you to use TLS client certificates for authentication, you can configure Argo CD repositories to make use of them. For this purpose, `--tls-client-cert-path` and `--tls-client-cert-key-path` switches to the `argocd repo add` command can be used to specify the files on your local system containing client certificate and the corresponding key, respectively: ``` argocd repo add https://repo.example.com/repo.git --tls-client-cert-path ~/mycert.crt --tls-client-cert-key-path ~/mycert.key @@ -63,7 +63,7 @@ Of course, you can also use this in combination with the `--username` and `--pas Your TLS client certificate and corresponding key can also be configured using the UI, see instructions for adding Git repos using HTTPS. !!! note - Your client certificate and key data must be in PEM format, other formats (such as PKCS12) are not understood. Also make sure that your certificate's key is not password protected, otherwise it cannot be used by ArgoCD. + Your client certificate and key data must be in PEM format, other formats (such as PKCS12) are not understood. Also make sure that your certificate's key is not password protected, otherwise it cannot be used by Argo CD. !!! note When pasting TLS client certificate and key in the text areas in the web UI, make sure they contain no unintended line breaks or additional characters. @@ -92,11 +92,11 @@ Using the UI: ![connect repo overview](../assets/repo-add-overview.png) -1. Click `Connect Repo using SSH` button, enter the URL and paste the SSH private key +2. Click `Connect Repo using SSH` button, enter the URL and paste the SSH private key ![connect repo](../assets/repo-add-ssh.png) -1. Click `Connect` to test the connection and have the repository added +3. Click `Connect` to test the connection and have the repository added !!!note When pasting SSH private key in the UI, make sure there are no unintended line breaks or additional characters in the text area @@ -125,11 +125,11 @@ Using the UI: ![connect repo overview](../assets/repo-add-overview.png) -1. Click `Connect Repo using GitHub App` button, enter the URL, App Id, Installation Id, and the app's private key. +2. Click `Connect Repo using GitHub App` button, enter the URL, App Id, Installation Id, and the app's private key. ![connect repo](../assets/repo-add-github-app.png) -1. Click `Connect` to test the connection and have the repository added +3. Click `Connect` to test the connection and have the repository added !!!note When pasting GitHub App private key in the UI, make sure there are no unintended line breaks or additional characters in the text area @@ -155,11 +155,11 @@ Using the UI: ![connect repo overview](../assets/repo-add-overview.png) -1. Click `Connect Repo using Google Cloud Source` button, enter the URL and the Google Cloud service account in JSON format. +2. Click `Connect Repo using Google Cloud Source` button, enter the URL and the Google Cloud service account in JSON format. ![connect repo](../assets/repo-add-google-cloud-source.png) -1. Click `Connect` to test the connection and have the repository added +3. Click `Connect` to test the connection and have the repository added ## Credential templates @@ -169,7 +169,7 @@ To set up a credential template using the Web UI, simply fill in all relevant cr To manage credential templates using the CLI, use the `repocreds` sub-command, for example `argocd repocreds add https://github.com/argoproj --username youruser --password yourpass` would setup a credential template for the URL prefix `https://github.com/argoproj` using the specified username/password combination. Similar to the `repo` sub-command, you can also list and remove repository credentials using the `argocd repocreds list` and `argocd repocreds rm` commands, respectively. -In order for ArgoCD to use a credential template for any given repository, the following conditions must be met: +In order for Argo CD to use a credential template for any given repository, the following conditions must be met: * The repository must either not be configured at all, or if configured, must not contain any credential information * The URL configured for a credential template (e.g. `https://github.com/argoproj`) must match as prefix for the repository URL (e.g. `https://github.com/argoproj/argocd-example-apps`). @@ -204,7 +204,7 @@ FATA[0000] rpc error: code = Unknown desc = authentication required ## Self-signed & Untrusted TLS Certificates -If you are connecting a repository on a HTTPS server using a self-signed certificate, or a certificate signed by a custom Certificate Authority (CA) which are not known to ArgoCD, the repository will not be added due to security reasons. This is indicated by an error message such as `x509: certificate signed by unknown authority`. +If you are connecting a repository on a HTTPS server using a self-signed certificate, or a certificate signed by a custom Certificate Authority (CA) which are not known to Argo CD, the repository will not be added due to security reasons. This is indicated by an error message such as `x509: certificate signed by unknown authority`. 1. You can let ArgoCD connect the repository in an insecure way, without verifying the server's certificate at all. This can be accomplished by using the `--insecure-skip-server-verification` flag when adding the repository with the `argocd` CLI utility. However, this should be done only for non-production setups, as it imposes a serious security issue through possible man-in-the-middle attacks. @@ -265,21 +265,21 @@ It is possible to add and remove TLS certificates using the ArgoCD web UI: 1. In the navigation pane to the left, click on "Settings" and choose "Certificates" from the settings menu -1. The following page lists all currently configured certificates and provides you with the option to add either a new TLS certificate or SSH known entries: +2. The following page lists all currently configured certificates and provides you with the option to add either a new TLS certificate or SSH known entries: ![manage certificates](../assets/cert-management-overview.png) -1. Click on "Add TLS certificate", fill in relevant data and click on "Create". Take care to specify only the FQDN of your repository server (not the URL) and that you C&P the complete PEM of your TLS certificate into the text area field, including the `----BEGIN CERTIFICATE----` and `----END CERTIFICATE----` lines: +3. Click on "Add TLS certificate", fill in relevant data and click on "Create". Take care to specify only the FQDN of your repository server (not the URL) and that you C&P the complete PEM of your TLS certificate into the text area field, including the `----BEGIN CERTIFICATE----` and `----END CERTIFICATE----` lines: ![add tls certificate](../assets/cert-management-add-tls.png) -1. To remove a certificate, click on the small three-dotted button next to the certificate entry, select "Remove" from the pop-up menu and confirm the removal in the following dialogue. +4. To remove a certificate, click on the small three-dotted button next to the certificate entry, select "Remove" from the pop-up menu and confirm the removal in the following dialogue. ![remove certificate](../assets/cert-management-remove.png) ### Managing TLS certificates using declarative configuration -You can also manage TLS certificates in a declarative, self-managed ArgoCD setup. All TLS certificates are stored in the ConfigMap object `argocd-tls-cert-cm`. +You can also manage TLS certificates in a declarative, self-managed ArgoCD setup. All TLS certificates are stored in the ConfigMap object `argocd-tls-certs-cm`. Please refer to the [Operator Manual](../../operator-manual/declarative-setup/#repositories-using-self-signed-tls-certificates-or-are-signed-by-custom-ca) for more information. ## Unknown SSH Hosts @@ -303,8 +303,8 @@ You can list all configured SSH known host entries using the `argocd cert list` ```bash $ argocd cert list --cert-type ssh HOSTNAME TYPE SUBTYPE FINGERPRINT/SUBJECT -bitbucket.org ssh ssh-rsa SHA256:zzXQOXSRBEiUtuE8AikJYKwbHaxvSc0ojez9YXaGp1A -github.com ssh ssh-rsa SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8 +bitbucket.org ssh ssh-rsa SHA256:46OSHA1Rmj8E8ERTC6xkNcmGOw9oFxYr0WF6zWW8l1E +github.com ssh ssh-rsa SHA256:uNiVztksCsDhcc0u9e8BujQXVUpKZIDTMczCvj3tD2s gitlab.com ssh ecdsa-sha2-nistp256 SHA256:HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw gitlab.com ssh ssh-ed25519 SHA256:eUXGGm1YGsMAS7vkcx6JOJdOGHPem5gQp4taiCfCLB8 gitlab.com ssh ssh-rsa SHA256:ROQFvPThGrW4RuWLoL9tq9I9zJ42fK4XywyRtbOz/EQ @@ -345,15 +345,15 @@ It is possible to add and remove SSH known hosts entries using the ArgoCD web UI 1. In the navigation pane to the left, click on "Settings" and choose "Certificates" from the settings menu -1. The following page lists all currently configured certificates and provides you with the option to add either a new TLS certificate or SSH known entries: +2. The following page lists all currently configured certificates and provides you with the option to add either a new TLS certificate or SSH known entries: ![manage certificates](../assets/cert-management-overview.png) -1. Click on "Add SSH known hosts" and paste your SSH known hosts data in the following mask. **Important**: Make sure there are no line breaks in the entries (key data) when you paste the data. Afterwards, click on "Create". +3. Click on "Add SSH known hosts" and paste your SSH known hosts data in the following mask. **Important**: Make sure there are no line breaks in the entries (key data) when you paste the data. Afterwards, click on "Create". ![manage ssh known hosts](../assets/cert-management-add-ssh.png) -1. To remove a certificate, click on the small three-dotted button next to the certificate entry, select "Remove" from the pop-up menu and confirm the removal in the following dialogue. +4. To remove a certificate, click on the small three-dotted button next to the certificate entry, select "Remove" from the pop-up menu and confirm the removal in the following dialogue. ![remove certificate](../assets/cert-management-remove.png) diff --git a/docs/user-guide/projects.md b/docs/user-guide/projects.md index 0973a19afe1fc..f5979cf3c47b3 100644 --- a/docs/user-guide/projects.md +++ b/docs/user-guide/projects.md @@ -3,8 +3,8 @@ Projects provide a logical grouping of applications, which is useful when Argo CD is used by multiple teams. Projects provide the following features: -* restrict *what* may be deployed (trusted Git source repositories) -* restrict *where* apps may be deployed to (destination clusters and namespaces) +* restrict what may be deployed (trusted Git source repositories) +* restrict where apps may be deployed to (destination clusters and namespaces) * restrict what kinds of objects may or may not be deployed (e.g. RBAC, CRDs, DaemonSets, NetworkPolicy etc...) * defining project roles to provide application RBAC (bound to OIDC groups and/or JWT tokens) @@ -271,15 +271,15 @@ projectName: `proj-global-test` should be replaced with your own global project ## Project scoped Repositories and Clusters -Normally, an ArgoCD admin creates a project and decides in advance which clusters and Git repositories +Normally, an Argo CD admin creates a project and decides in advance which clusters and Git repositories it defines. However, this creates a problem in scenarios where a developer wants to add a repository or cluster -after the initial creation of the project. This forces the developer to contact their ArgoCD admin again to update the project definition. +after the initial creation of the project. This forces the developer to contact their Argo CD admin again to update the project definition. It is possible to offer a self-service process for developers so that they can add a repository and/or cluster in a project on their own even after the initial creation of the project. -For this purpose ArgoCD supports project-scoped repositories and clusters. +For this purpose Argo CD supports project-scoped repositories and clusters. -To begin the process, ArgoCD admins must configure RBAC security to allow this self-service behavior. +To begin the process, Argo CD admins must configure RBAC security to allow this self-service behavior. For example, to allow users to add project scoped repositories and admin would have to add the following RBAC rules: @@ -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,7 +321,29 @@ stringData: All the examples above talk about Git repositories, but the same principles apply to clusters as well. -With cluster-scoped clusters we can also restrict projects to only allow applications whose destinations belong to the +```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: @@ -346,4 +368,4 @@ spec: ``` With this set, the application above would no longer be allowed to be synced to any cluster other than the ones which -are a part of the same project. \ No newline at end of file +are a part of the same project. diff --git a/docs/user-guide/resource_hooks.md b/docs/user-guide/resource_hooks.md index 9f8f98e033a20..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. @@ -69,7 +73,7 @@ The following policies define when the hook will be deleted. | `HookFailed` | The hook resource is deleted after the hook failed. | | `BeforeHookCreation` | Any existing hook resource is deleted before the new one is created (since v1.3). It is meant to be used with `/metadata/name`. | -Note that if no deletion policy is specified, ArgoCD will automatically assume `BeforeHookCreation` rules. +Note that if no deletion policy is specified, Argo CD will automatically assume `BeforeHookCreation` rules. ### Sync Status with Jobs/Workflows with Time to Live (ttl) diff --git a/docs/user-guide/resource_tracking.md b/docs/user-guide/resource_tracking.md index cb69ef143d7a2..e62a7c094f4e2 100644 --- a/docs/user-guide/resource_tracking.md +++ b/docs/user-guide/resource_tracking.md @@ -24,6 +24,22 @@ There are however several limitations: * Other external tools might write/append to this label and create conflicts with Argo CD. For example several Helm charts and operators also use this label for generated manifests confusing Argo CD about the owner of the application * You might want to deploy more than one Argo CD instance on the same cluster (with cluster wide privileges) and have an easy way to identify which resource is managed by which instance of Argo CD +### Use custom label + +Instead of using the default `app.kubernetes.io/instance` label for resource tracking, Argo CD can be configured to use a custom label. Below example sets the resource tracking label to `argocd.argoproj.io/instance`. + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cm + labels: + app.kubernetes.io/name: argocd-cm + app.kubernetes.io/part-of: argocd +data: + application.instanceLabelKey: argocd.argoproj.io/instance +``` + ## Additional tracking methods via an annotation >v2.2 @@ -49,18 +65,28 @@ metadata: The advantages of using the tracking id annotation is that there are no clashes any more with other Kubernetes tools and Argo CD is never confused about the owner of a resource. The `annotation+label` can also be used if you want other tools to understand resources managed by Argo CD. +### Non self-referencing annotations +When using the tracking method `annotation` or `annotation+label`, Argo CD will consider the resource properties in the annotation (name, namespace, group and kind) to determine whether the resource should be compared against the desired state. If the tracking annotation does not reference the resource it is applied to, the resource will neither affect the application's sync status nor be marked for pruning. + +This allows other kubernetes tools (e.g. [HNC](https://github.com/kubernetes-sigs/hierarchical-namespaces)) to copy a resource to a different namespace without impacting the Argo CD application's sync status. Copied resources will be visible on the UI at top level. They will have no sync status and won't impact the application's sync status. + ## Choosing a tracking method To actually select your preferred tracking method edit the `resourceTrackingMethod` value contained inside the `argocd-cm` configmap. ```yaml apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cm + labels: + app.kubernetes.io/name: argocd-cm + app.kubernetes.io/part-of: argocd data: application.resourceTrackingMethod: annotation -kind: ConfigMap ``` Possible values are `label`, `annotation+label` and `annotation` as described in the previous section. Note that once you change the value you need to sync your applications again (or wait for the sync mechanism to kick-in) in order to apply your changes. -You can revert to a previous choice, by changing again the configmap. \ No newline at end of file +You can revert to a previous choice, by changing again the configmap. diff --git a/docs/user-guide/skip_reconcile.md b/docs/user-guide/skip_reconcile.md new file mode 100644 index 0000000000000..d5eec86a6a866 --- /dev/null +++ b/docs/user-guide/skip_reconcile.md @@ -0,0 +1,70 @@ +# Skip Application Reconcile + +!!! warning "Alpha Feature" + This is an experimental, alpha-quality feature. + The primary use case is to provide integration with third party projects. + This feature may be removed in future releases or modified in backwards-incompatible ways. + +Argo CD allows users to stop an Application from reconciling. +The skip reconcile option is configured with the `argocd.argoproj.io/skip-reconcile: "true"` annotation. +When the Application is configured to skip reconcile, +all processing is stopped for the Application. +During the period of time when the Application is not processing, +the Application `status` field will not be updated. +If an Application is newly created with the skip reconcile annotation, +then the Application `status` field will not be present. +To resume the reconciliation or processing of the Application, +remove the annotation or set the value to `"false"`. + +See the below example for enabling an Application to skip reconcile: + +```yaml +metadata: + annotations: + argocd.argoproj.io/skip-reconcile: "true" +``` + +See the below example for an Application that is newly created with the skip reconcile enabled: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/skip-reconcile: "true" + name: guestbook + namespace: argocd +spec: + destination: + namespace: guestbook + server: https://kubernetes.default.svc + project: default + source: + path: guestbook + repoURL: https://github.com/argoproj/argocd-example-apps.git + targetRevision: HEAD +``` + +The `status` field is not present. + +## Primary Use Case + +The skip reconcile option is intended to be used with third party projects that wishes +to make updates to the Application status without having the changes being overwritten by the Application controller. +An example of this usage is the [Open Cluster Management (OCM)](https://github.com/open-cluster-management-io/) project using +[pull-integration](https://github.com/open-cluster-management-io/argocd-pull-integration) controller. +In the example, the hub cluster Application is not meant to be reconciled by the Argo CD Application controller. +Instead, the OCM pull-integration controller will populate the primary/hub cluster Application status +using the collected Application status from the remote/spoke/managed cluster. + +## Alternative Use Cases + +There are other alternative use cases for this skip reconcile option. +It's important to note that this is an experimental, alpha-quality feature +and the following use cases are generally not recommended. + +* Ease of debugging when the Application reconcile is skipped. +* Orphan resources without deleting the Application might provide a safer way to migrate applications. +* ApplicationSet can generate dry-run like Applications that don't reconcile automatically. +* Pause and resume Applications reconcile during a disaster recovery process. +* Provide another alternative approval flow by not allowing an Application to start reconciling right away. diff --git a/docs/user-guide/status-badge.md b/docs/user-guide/status-badge.md index 8355be458f026..3363227997309 100644 --- a/docs/user-guide/status-badge.md +++ b/docs/user-guide/status-badge.md @@ -9,7 +9,12 @@ To show this badge, use the following URL format `${argoCdBaseUrl}/api/badge?nam The URLs for status image are available on application details page: 1. Navigate to application details page and click on 'Details' button. -1. Scroll down to 'Status Badge' section. -1. Select required template such as URL, Markdown etc. +2. Scroll down to 'Status Badge' section. +3. Select required template such as URL, Markdown etc. for the status image URL in markdown, html, etc are available . -1. Copy the text and paste it into your README or website. \ No newline at end of file +4. Copy the text and paste it into your README or website. + +The application name may optionally be displayed in the status badge by adding the `?showAppName=true` query parameter. + +For example, `${argoCdBaseUrl}/api/badge?name=${appName}&showAppName=true`. +To remove the application name from the badge, remove the query parameter from the URL or set it to `false`. \ No newline at end of file diff --git a/docs/user-guide/sync-kubectl.md b/docs/user-guide/sync-kubectl.md new file mode 100644 index 0000000000000..100ec2cdf70b1 --- /dev/null +++ b/docs/user-guide/sync-kubectl.md @@ -0,0 +1,144 @@ +# Sync Applications with Kubectl + +You can use "kubectl" to ask Argo CD to synchronize applications the same way you can use the CLI or UI. Many configurations like "force", "prune", "apply" and even synchronize a specific list of resources are equally supported. This is done by applying or patching the Argo CD application with a document that defines an "operation". + +This "operation" defines how a synchronization should be done and for what resources these synchronization is to be done. + +There are many configuration options that can be added to the "operation". Next, a few of them are explained. For more details, you can have a look at the CRD [applications.argoproj.io](https://github.com/argoproj/argo-cd/blob/master/manifests/crds/application-crd.yaml). Some of them are required, whereas others are optional. + +To ask Argo CD to synchronize all resources of a given application, we can do: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: + namespace: +spec: + ... +operation: + initiatedBy: + username: + sync: + syncStrategy: + hook: {} +``` + +```bash +$ kubectl apply -f +``` + +The most important part is the "sync" definition in the "operation" field. You can pass optional information like "info" or "initiatedBy". "info" allows you to add information about the operation in the form of a list. "initiatedBy" contains information about who initiated the operation request. + +Or if you prefer, you also can patch: + +```yaml +operation: + initiatedBy: + username: + sync: + syncStrategy: + hook: {} +``` + +```bash +$ kubectl patch -n app --patch-file --type merge +``` + +Be aware that patches, specially with merge strategies, may not work the way you expect especially if you change sync strategies or options. +In these cases, "kubectl apply" gives better results. + +Either with a "kubectl patch" or "kubectl apply", the state of the synchronization is reported in the "operationState" field in the application object. + +```bash +$ kubectl get -n get app -o yaml +... +status: + operationState: + finishedAt: "2023-08-03T11:16:17Z" + message: successfully synced (all tasks run) + phase: Succeeded +``` + +# Apply and Hook synchronization strategies + +There are two types of synchronization strategies: "hook", which is the default value, and "apply". + +An "apply" sync strategy tells Argo CD to "kubectl apply", whereas a "hook" sync strategy informs Argo CD to submit any resource that's referenced in the operation. This way the synchronization of these resources will take into consideration any hook the resource has been annotated with. + +```yaml +operation: + sync: + syncStrategy: + apply: {} +``` + +```yaml +operation: + sync: + syncStrategy: + hook: {} +``` + +Both strategies support "force". However, you need to be aware that a force operation deletes the resource when patch encounters a conflict after having retried 5 times. + +```yaml +operation: + sync: + syncStrategy: + apply: + force: true +``` + +```yaml +operation: + sync: + syncStrategy: + hook: + force: true +``` + +# Prune + +If you want to prune your resources before applying, you can instruct Argo CD to do so: + +```yaml +operation: + sync: + prune: true +``` + +# List of resources + +There's always the possibility to pass a list of resources. This list can be all resources the application manages or only a subset, for example resources that remained out of sync for some reason. + +Only "kind" and "name" are required fields when referencing resources, but the fields "groups" and "namespace" can also be defined: + +```yaml +operation: + sync: + resources: + - kind: Namespace + name: namespace-name + - kind: ServiceAccount + name: service-account-name + namespace: namespace-name + - group: networking.k8s.io + kind: NetworkPolicy + name: network-policy-name + namespace: namespace-name +``` + +# Sync Options + +In an operation, you can also pass sync-options. Each of these options is passed as "name=value" pairs. For example: + +```yaml +operations: + sync: + syncOptions: + - Validate=false + - Prune=false +``` + +For more information about sync options, please refer to [sync-options](https://argo-cd.readthedocs.io/en/stable/user-guide/sync-options/) diff --git a/docs/user-guide/sync-options.md b/docs/user-guide/sync-options.md index 098291e80d28b..a563821967d04 100644 --- a/docs/user-guide/sync-options.md +++ b/docs/user-guide/sync-options.md @@ -1,6 +1,6 @@ # Sync Options -Argo CD allows users to customize some aspects of how it syncs the desired state in the target cluster. Some Sync Options can defined as annotations in a specific resource. Most of the Sync Options are configured in the Application resource `spec.syncPolicy.syncOptions` attribute. Multiple Sync Options which are configured with the `argocd.argoproj.io/sync-options` annotation can be concatenated with a `,` in the annotation value; white spaces will be trimmed. +Argo CD allows users to customize some aspects of how it syncs the desired state in the target cluster. Some Sync Options can be defined as annotations in a specific resource. Most of the Sync Options are configured in the Application resource `spec.syncPolicy.syncOptions` attribute. Multiple Sync Options which are configured with the `argocd.argoproj.io/sync-options` annotation can be concatenated with a `,` in the annotation value; white spaces will be trimmed. Below you can find details about each available Sync Option: @@ -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 @@ -58,6 +58,18 @@ metadata: The dry run will still be executed if the CRD is already present in the cluster. +## No Resource Deletion + +For certain resources you might want to retain them even after your application is deleted, for eg. Persistent Volume Claims. +In such situations you can stop those resources from being cleaned up during app deletion by using the following annotation: + + +```yaml +metadata: + annotations: + argocd.argoproj.io/sync-options: Delete=false +``` + ## Selective Sync Currently when syncing using auto sync Argo CD applies every object in the application. @@ -258,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 @@ -304,10 +316,10 @@ spec: - CreateNamespace=true ``` -In order for ArgoCD to manage the labels and annotations on the namespace, `CreateNamespace=true` needs to be set as a +In order for Argo CD to manage the labels and annotations on the namespace, `CreateNamespace=true` needs to be set as a sync option, otherwise nothing will happen. If the namespace doesn't already exist, or if it already exists and doesn't already have labels and/or annotations set on it, you're good to go. Using `managedNamespaceMetadata` will also set the -resource tracking label (or annotation) on the namespace, so you can easily track which namespaces are managed by ArgoCD. +resource tracking label (or annotation) on the namespace, so you can easily track which namespaces are managed by Argo CD. In the case you do not have any custom annotations or labels but would nonetheless want to have resource tracking set on your namespace, that can be done by setting `managedNamespaceMetadata` with an empty `labels` and/or `annotations` map, @@ -327,53 +339,13 @@ spec: - CreateNamespace=true ``` -In the case where ArgoCD 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 ArgoCD 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 ArgoCD application, that +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 you have an application that sets `managedNamespaceMetadata` 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 8129e78c27062..f6bc6b82f8b69 100644 --- a/docs/user-guide/sync_windows.md +++ b/docs/user-guide/sync_windows.md @@ -7,7 +7,7 @@ of both manual and automated syncs but allow an override for manual syncs which in preventing automated syncs or if you need to temporarily override a window to perform a sync. The windows work in the following way. If there are no windows matching an application then all syncs are allowed. If there -are any `allow` windows matching an application then syncs will only be allowed when there is an active `allow` windows. If there +are any `allow` windows matching an application then syncs will only be allowed when there is an active `allow` window. If there are any `deny` windows matching an application then all syncs will be denied when the `deny` windows are active. If there is an active matching `allow` and an active matching `deny` then syncs will be denied as `deny` windows override `allow` windows. The UI and the CLI will both display the state of the sync windows. The UI has a panel which will display different colours depending @@ -64,6 +64,7 @@ spec: manualSync: true - kind: deny schedule: '0 22 * * *' + timeZone: "Europe/Amsterdam" duration: 1h namespaces: - default diff --git a/docs/user-guide/tracking_strategies.md b/docs/user-guide/tracking_strategies.md index e1abe85717724..57dfc5f907b65 100644 --- a/docs/user-guide/tracking_strategies.md +++ b/docs/user-guide/tracking_strategies.md @@ -11,7 +11,7 @@ is detected. ## Helm -For Helm, all versions are [Semantic Versions](https://semver.org/). As a result, you can either version ranges: +Helm chart versions are [Semantic Versions](https://semver.org/). As a result, you can use any of the following version ranges: | Use Case | How | Examples | |-|-|-| @@ -19,6 +19,7 @@ For Helm, all versions are [Semantic Versions](https://semver.org/). As a result | Track patches (e.g. in pre-production) | Use a range | `1.2.*` or `>=1.2.0 <1.3.0` | | Track minor releases (e.g. in QA) | Use a range | `1.*` or `>=1.0.0 <2.0.0` | | Use the latest (e.g. in local development) | Use star range | `*` or `>=0.0.0` | +| Use the latest including pre-releases | Use star range with `-0` suffix | `*-0` or `>=0.0.0-0` | [Read about version ranges](https://www.telerik.com/blogs/the-mystical-magical-semver-ranges-used-by-npm-bower) diff --git a/entrypoint.sh b/entrypoint.sh index 88515e217e4be..24862aca2172d 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # If we're started as PID 1, we should wrap command execution through tini to # prevent leakage of orphaned processes ("zombies"). diff --git a/examples/dashboard.json b/examples/dashboard.json index 7e992a5363324..108ac81918ba3 100644 --- a/examples/dashboard.json +++ b/examples/dashboard.json @@ -3,7 +3,10 @@ "list": [ { "builtIn": 1, - "datasource": "-- Grafana --", + "datasource": { + "type": "datasource", + "uid": "grafana" + }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", @@ -13,15 +16,17 @@ ] }, "editable": true, - "gnetId": null, + "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 1, - "iteration": 1605574886303, + "id": 28, "links": [], + "liveNow": false, "panels": [ { "collapsed": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "gridPos": { "h": 1, "w": 24, @@ -30,12 +35,21 @@ }, "id": 68, "panels": [], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], "title": "Overview", "type": "row" }, { - "content": "![argoimage](https://avatars1.githubusercontent.com/u/30269780?s=110&v=4)", - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "gridPos": { "h": 4, "w": 2, @@ -44,29 +58,64 @@ }, "id": 26, "links": [], - "mode": "markdown", - "options": {}, - "title": "", + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "![argoimage](https://avatars1.githubusercontent.com/u/30269780?s=110&v=4)", + "mode": "markdown" + }, + "pluginVersion": "10.3.1", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], "transparent": true, "type": "text" }, { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": false, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], - "datasource": "$datasource", - "format": "dtdurations", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": false, - "thresholdLabels": false, - "thresholdMarkers": true + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "dtdurations", + "unitScale": true + }, + "overrides": [] }, "gridPos": { "h": 4, @@ -75,79 +124,77 @@ "y": 1 }, "id": 32, - "interval": null, "links": [], - "mappingType": 1, - "mappingTypes": [ - { - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "options": {}, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [ - { - "from": "null", - "text": "N/A", - "to": "null" - } - ], - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": false + "options": { + "colorMode": "none", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true }, - "tableColumn": "", + "pluginVersion": "10.3.1", "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "time() - max(process_start_time_seconds{job=\"argocd-server-metrics\",namespace=~\"$namespace\"})", "format": "time_series", "intervalFactor": 1, "refId": "A" } ], - "thresholds": "", "title": "Uptime", - "type": "singlestat", - "valueFontSize": "70%", - "valueMaps": [ - { - "op": "=", - "text": "N/A", - "value": "null" - } - ], - "valueName": "current" + "type": "stat" }, { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": false, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], - "datasource": "$datasource", - "format": "none", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": false, - "thresholdLabels": false, - "thresholdMarkers": true + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "0" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none", + "unitScale": true + }, + "overrides": [] }, "gridPos": { "h": 4, @@ -156,43 +203,30 @@ "y": 1 }, "id": 94, - "interval": null, "links": [], - "mappingType": 1, - "mappingTypes": [ - { - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "options": {}, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [ - { - "from": "null", - "text": "N/A", - "to": "null" - } - ], - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": true + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true }, - "tableColumn": "", + "pluginVersion": "10.3.1", "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "count(count by (server) (argocd_cluster_info{namespace=~\"$namespace\"}))", "format": "time_series", "instant": false, @@ -200,40 +234,47 @@ "refId": "A" } ], - "thresholds": "", - "timeFrom": null, - "timeShift": null, "title": "Clusters", - "type": "singlestat", - "valueFontSize": "80%", - "valueMaps": [ - { - "op": "=", - "text": "0", - "value": "null" - } - ], - "valueName": "current" + "type": "stat" }, { - "cacheTimeout": null, - "colorBackground": false, - "colorPostfix": false, - "colorPrefix": false, - "colorValue": false, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], - "datasource": "$datasource", - "format": "none", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": false, - "thresholdLabels": false, - "thresholdMarkers": true + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "N/A" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none", + "unitScale": true + }, + "overrides": [] }, "gridPos": { "h": 4, @@ -242,45 +283,31 @@ "y": 1 }, "id": 75, - "interval": null, "links": [], - "mappingType": 1, - "mappingTypes": [ - { - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "options": {}, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [ - { - "from": "null", - "text": "N/A", - "to": "null" - } - ], - "repeat": null, - "repeatDirection": "h", - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": true + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true }, - "tableColumn": "", + "pluginVersion": "10.3.1", + "repeatDirection": "h", "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(argocd_app_info{namespace=~\"$namespace\",dest_server=~\"$cluster\",health_status=~\"$health_status\",sync_status=~\"$sync_status\"})", "format": "time_series", "instant": false, @@ -288,38 +315,47 @@ "refId": "A" } ], - "thresholds": "", - "timeFrom": null, - "timeShift": null, "title": "Applications", - "type": "singlestat", - "valueFontSize": "80%", - "valueMaps": [ - { - "op": "=", - "text": "N/A", - "value": "null" - } - ], - "valueName": "current" + "type": "stat" }, { - "cacheTimeout": null, - "colorBackground": false, - "colorValue": false, - "colors": [ - "#299c46", - "rgba(237, 129, 40, 0.89)", - "#d44a3a" - ], - "datasource": "$datasource", - "format": "none", - "gauge": { - "maxValue": 100, - "minValue": 0, - "show": false, - "thresholdLabels": false, - "thresholdMarkers": true + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgb(31, 120, 193)", + "mode": "fixed" + }, + "mappings": [ + { + "options": { + "match": "null", + "result": { + "text": "0" + } + }, + "type": "special" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none", + "unitScale": true + }, + "overrides": [] }, "gridPos": { "h": 4, @@ -328,43 +364,30 @@ "y": 1 }, "id": 107, - "interval": null, "links": [], - "mappingType": 1, - "mappingTypes": [ - { - "name": "value to text", - "value": 1 - }, - { - "name": "range to text", - "value": 2 - } - ], "maxDataPoints": 100, - "nullPointMode": "connected", - "nullText": null, - "options": {}, - "postfix": "", - "postfixFontSize": "50%", - "prefix": "", - "prefixFontSize": "50%", - "rangeMaps": [ - { - "from": "null", - "text": "N/A", - "to": "null" - } - ], - "sparkline": { - "fillColor": "rgba(31, 118, 189, 0.18)", - "full": false, - "lineColor": "rgb(31, 120, 193)", - "show": true + "options": { + "colorMode": "none", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true }, - "tableColumn": "", + "pluginVersion": "10.3.1", "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "count(count by (repo) (argocd_app_info{namespace=~\"$namespace\"}))", "format": "time_series", "instant": false, @@ -372,24 +395,47 @@ "refId": "A" } ], - "thresholds": "", - "timeFrom": null, - "timeShift": null, "title": "Repositories", - "type": "singlestat", - "valueFontSize": "80%", - "valueMaps": [ - { - "op": "=", - "text": "0", - "value": "null" - } - ], - "valueName": "current" + "type": "stat" }, { - "cacheTimeout": null, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "0", + "type": 1, + "value": "null" + } + ], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none", + "unitScale": true + }, + "overrides": [] + }, "gridPos": { "h": 4, "w": 3, @@ -399,47 +445,27 @@ "id": 100, "links": [], "options": { - "fieldOptions": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "horizontal", + "reduceOptions": { "calcs": [ "lastNotNull" ], - "defaults": { - "mappings": [ - { - "id": 0, - "op": "=", - "text": "0", - "type": 1, - "value": "null" - } - ], - "max": 100, - "min": 0, - "nullValueMode": "connected", - "thresholds": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ], - "unit": "none" - }, - "override": {}, - "overrides": [], + "fields": "", "values": false }, - "orientation": "horizontal", "showThresholdLabels": false, - "showThresholdMarkers": true + "showThresholdMarkers": true, + "sizing": "auto" }, - "pluginVersion": "6.5.2", + "pluginVersion": "10.3.1", "repeatDirection": "h", "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(argocd_app_info{namespace=~\"$namespace\",dest_server=~\"$cluster\",operation!=\"\"})", "format": "time_series", "instant": true, @@ -448,19 +474,24 @@ "refId": "A" } ], - "timeFrom": null, - "timeShift": null, "title": "Operations", "type": "gauge" }, { "aliasColors": {}, "bars": false, - "cacheTimeout": null, "dashLength": 10, "dashes": false, - "datasource": "$datasource", - "decimals": null, + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, "fill": 1, "fillGradient": 0, "gridPos": { @@ -491,10 +522,11 @@ "links": [], "nullPointMode": "connected", "options": { - "dataLinks": [] + "alertThreshold": true }, "paceLength": 10, "percentage": false, + "pluginVersion": "10.3.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -504,6 +536,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(argocd_app_info{namespace=~\"$namespace\",dest_server=~\"$cluster\",health_status=~\"$health_status\",sync_status=~\"$sync_status\"}) by (namespace)", "format": "time_series", "instant": false, @@ -513,9 +548,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Applications", "tooltip": { "shared": false, @@ -524,9 +557,7 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, @@ -534,29 +565,24 @@ { "decimals": 0, "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { "collapsed": true, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "gridPos": { "h": 1, "w": 24, @@ -575,11 +601,18 @@ "Unknown": "rgb(255, 255, 255)" }, "bars": false, - "cacheTimeout": null, "dashLength": 10, "dashes": false, - "datasource": "$datasource", - "decimals": null, + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, "fill": 1, "fillGradient": 0, "gridPos": { @@ -601,7 +634,6 @@ "min": false, "rightSide": true, "show": true, - "sideWidth": null, "sort": "current", "sortDesc": true, "total": false, @@ -612,10 +644,11 @@ "links": [], "nullPointMode": "null as zero", "options": { - "dataLinks": [] + "alertThreshold": true }, "paceLength": 10, "percentage": false, + "pluginVersion": "10.3.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -625,6 +658,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(argocd_app_info{namespace=~\"$namespace\",dest_server=~\"$cluster\",health_status=~\"$health_status\",sync_status=~\"$sync_status\",health_status!=\"\"}) by (health_status)", "format": "time_series", "instant": false, @@ -634,9 +670,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Health Status", "tooltip": { "shared": true, @@ -645,33 +679,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 2, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -686,11 +711,18 @@ "Unknown": "rgb(255, 255, 255)" }, "bars": false, - "cacheTimeout": null, "dashLength": 10, "dashes": false, - "datasource": "$datasource", - "decimals": null, + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, "fill": 1, "fillGradient": 0, "gridPos": { @@ -712,7 +744,6 @@ "min": false, "rightSide": true, "show": true, - "sideWidth": null, "sort": "current", "sortDesc": true, "total": false, @@ -723,10 +754,11 @@ "links": [], "nullPointMode": "null as zero", "options": { - "dataLinks": [] + "alertThreshold": true }, "paceLength": 10, "percentage": false, + "pluginVersion": "10.3.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -736,6 +768,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(argocd_app_info{namespace=~\"$namespace\",dest_server=~\"$cluster\",health_status=~\"$health_status\",sync_status=~\"$sync_status\",health_status!=\"\"}) by (sync_status)", "format": "time_series", "instant": false, @@ -745,9 +780,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Sync Status", "tooltip": { "shared": true, @@ -756,42 +789,43 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 2, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], "title": "Application Status", "type": "row" }, { "collapsed": true, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "gridPos": { "h": 1, "w": 24, @@ -805,8 +839,9 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", - "decimals": null, + "datasource": { + "uid": "$datasource" + }, "fill": 1, "fillGradient": 0, "gridPos": { @@ -851,6 +886,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(round(increase(argocd_app_sync_total{namespace=~\"$namespace\",dest_server=~\"$cluster\"}[$interval]))) by ($grouping)", "format": "time_series", "intervalFactor": 1, @@ -859,9 +897,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Sync Activity", "tooltip": { "shared": true, @@ -870,9 +906,7 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, @@ -882,7 +916,6 @@ "format": "short", "label": "", "logBase": 1, - "max": null, "min": "0", "show": true }, @@ -891,14 +924,11 @@ "format": "short", "label": "", "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -906,8 +936,9 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", - "decimals": null, + "datasource": { + "uid": "$datasource" + }, "fill": 1, "fillGradient": 0, "gridPos": { @@ -951,6 +982,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(round(increase(argocd_app_sync_total{namespace=~\"$namespace\",phase=~\"Error|Failed\",dest_server=~\"$cluster\"}[$interval]))) by ($grouping, phase)", "format": "time_series", "intervalFactor": 1, @@ -959,9 +993,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Sync Failures", "tooltip": { "shared": true, @@ -970,9 +1002,7 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, @@ -982,7 +1012,6 @@ "format": "none", "label": "", "logBase": 1, - "max": null, "min": "0", "show": true }, @@ -990,23 +1019,30 @@ "format": "short", "label": "", "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], "title": "Sync Stats", "type": "row" }, { "collapsed": true, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "gridPos": { "h": 1, "w": 24, @@ -1020,7 +1056,9 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "fillGradient": 0, "gridPos": { @@ -1062,6 +1100,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(argocd_app_reconcile_count{namespace=~\"$namespace\",dest_server=~\"$cluster\"}[$interval])) by ($grouping)", "format": "time_series", "intervalFactor": 1, @@ -1070,9 +1111,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Reconciliation Activity", "tooltip": { "shared": false, @@ -1081,50 +1120,39 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { - "cards": { - "cardPadding": null, - "cardRound": null - }, + "cards": {}, "color": { "cardColor": "#b4ff00", "colorScale": "sqrt", "colorScheme": "interpolateSpectral", "exponent": 0.5, - "min": null, "mode": "spectrum" }, "dataFormat": "tsbuckets", - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "gridPos": { "h": 7, "w": 24, @@ -1143,6 +1171,9 @@ "reverseYBuckets": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(argocd_app_reconcile_bucket{namespace=~\"$namespace\"}[$interval])) by (le)", "format": "heatmap", "instant": false, @@ -1151,8 +1182,6 @@ "refId": "A" } ], - "timeFrom": null, - "timeShift": null, "title": "Reconciliation Performance", "tooltip": { "show": true, @@ -1163,27 +1192,21 @@ "xAxis": { "show": true }, - "xBucketNumber": null, - "xBucketSize": null, "yAxis": { - "decimals": null, "format": "short", "logBase": 1, - "max": null, - "min": null, - "show": true, - "splitFactor": null + "show": true }, - "yBucketBound": "auto", - "yBucketNumber": null, - "yBucketSize": null + "yBucketBound": "auto" }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "fillGradient": 0, "gridPos": { @@ -1204,7 +1227,6 @@ "min": false, "rightSide": true, "show": true, - "sideWidth": null, "sort": "current", "sortDesc": true, "total": false, @@ -1215,11 +1237,315 @@ "links": [], "nullPointMode": "null as zero", "options": { - "dataLinks": [] + "dataLinks": [] + }, + "paceLength": 10, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(increase(argocd_app_k8s_request_total{namespace=~\"$namespace\",server=~\"$cluster\"}[$interval])) by (verb, resource_kind)", + "format": "time_series", + "instant": false, + "intervalFactor": 1, + "legendFormat": "{{verb}} {{resource_kind}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "K8s API Activity", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "show": true + }, + { + "format": "short", + "logBase": 1, + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 31 + }, + "hiddenSeries": false, + "id": 96, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideZero": true, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(workqueue_depth{namespace=~\"$namespace\",name=~\"app_.*\"}) by (name)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{name}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Workqueue Depth", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + }, + { + "format": "short", + "logBase": 1, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 31 + }, + "hiddenSeries": false, + "id": 98, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideZero": false, + "max": true, + "min": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(argocd_kubectl_exec_pending{namespace=~\"$namespace\"}) by (command)", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{command}}", + "refId": "A" + } + ], + "thresholds": [], + "timeRegions": [], + "title": "Pending kubectl run", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "min": "0", + "show": true + }, + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "min": "0", + "show": true + } + ], + "yaxis": { + "align": false + } + } + ], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Controller Stats", + "type": "row" + }, + { + "collapsed": true, + "datasource": { + "uid": "$datasource" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 102, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 9 + }, + "hiddenSeries": false, + "id": 34, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "sort": "current", + "sortDesc": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "alertThreshold": true }, "paceLength": 10, "percentage": false, - "pointradius": 2, + "pluginVersion": "10.3.1", + "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], @@ -1228,53 +1554,44 @@ "steppedLine": false, "targets": [ { - "expr": "sum(increase(argocd_app_k8s_request_total{namespace=~\"$namespace\",server=~\"$cluster\"}[$interval])) by (verb, resource_kind)", + "datasource": { + "uid": "$datasource" + }, + "expr": "go_memstats_heap_alloc_bytes{job=\"argocd-server-metrics\",namespace=~\"$namespace\"}", "format": "time_series", - "instant": false, "intervalFactor": 1, - "legendFormat": "{{verb}} {{resource_kind}}", + "legendFormat": "{{namespace}}", "refId": "A" } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, - "title": "K8s API Activity", + "title": "Memory Usage", "tooltip": { - "shared": true, + "shared": false, "sort": 2, "value_type": "individual" }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { - "format": "short", - "label": null, + "format": "bytes", "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1282,39 +1599,52 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 7, - "w": 12, + "w": 24, "x": 0, - "y": 31 + "y": 16 }, "hiddenSeries": false, - "id": 96, + "id": 108, "legend": { "alignAsTable": true, "avg": true, "current": true, + "hideEmpty": true, "hideZero": true, "max": true, "min": false, - "rightSide": false, + "rightSide": true, "show": true, - "sideWidth": null, + "sort": "avg", + "sortDesc": true, "total": false, "values": true }, "lines": true, "linewidth": 1, "links": [], - "nullPointMode": "null", + "nullPointMode": "connected", "options": { - "dataLinks": [] + "alertThreshold": true }, + "paceLength": 10, "percentage": false, - "pointradius": 2, + "pluginVersion": "10.3.1", + "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], @@ -1323,52 +1653,45 @@ "steppedLine": false, "targets": [ { - "expr": "sum(workqueue_depth{namespace=~\"$namespace\",name=~\"app_.*\"}) by (name)", + "datasource": { + "uid": "$datasource" + }, + "expr": "irate(process_cpu_seconds_total{job=\"argocd-server-metrics\",namespace=~\"$namespace\"}[1m])", "format": "time_series", "intervalFactor": 1, - "legendFormat": "{{name}}", + "legendFormat": "{{namespace}}", "refId": "A" } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, - "title": "Workqueue Depth", + "title": "CPU Usage", "tooltip": { - "shared": true, + "shared": false, "sort": 2, "value_type": "individual" }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { - "format": "short", - "label": null, + "decimals": 1, + "format": "none", "logBase": 1, - "max": null, - "min": "0", "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": "0", "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1376,26 +1699,38 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", - "decimals": null, + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 7, - "w": 12, - "x": 12, - "y": 31 + "w": 24, + "x": 0, + "y": 23 }, "hiddenSeries": false, - "id": 98, + "id": 62, "legend": { "alignAsTable": true, "avg": true, "current": true, + "hideEmpty": false, "hideZero": false, "max": true, "min": false, + "rightSide": true, "show": true, + "sort": "current", + "sortDesc": true, "total": false, "values": true }, @@ -1404,10 +1739,12 @@ "links": [], "nullPointMode": "null", "options": { - "dataLinks": [] + "alertThreshold": true }, + "paceLength": 10, "percentage": false, - "pointradius": 2, + "pluginVersion": "10.3.1", + "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], @@ -1416,63 +1753,64 @@ "steppedLine": false, "targets": [ { - "expr": "sum(argocd_kubectl_exec_pending{namespace=~\"$namespace\"}) by (command)", + "datasource": { + "uid": "$datasource" + }, + "expr": "go_goroutines{job=\"argocd-server-metrics\",namespace=~\"$namespace\"}", "format": "time_series", "intervalFactor": 1, - "legendFormat": "{{command}}", + "legendFormat": "{{namespace}}", "refId": "A" } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, - "title": "Pending kubectl run", + "title": "Goroutines", "tooltip": { - "shared": true, + "shared": false, "sort": 2, "value_type": "individual" }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { - "decimals": 0, "format": "short", - "label": "", "logBase": 1, - "max": null, - "min": "0", "show": true }, { - "decimals": 0, "format": "short", - "label": "", "logBase": 1, - "max": null, - "min": "0", "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], - "title": "Controller Stats", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "Controller Telemetry", "type": "row" }, + { "collapsed": true, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "gridPos": { "h": 1, "w": 24, @@ -1486,14 +1824,23 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 7, "w": 24, "x": 0, - "y": 26 + "y": 9 }, "hiddenSeries": false, "id": 34, @@ -1515,10 +1862,11 @@ "links": [], "nullPointMode": "connected", "options": { - "dataLinks": [] + "alertThreshold": true }, "paceLength": 10, "percentage": false, + "pluginVersion": "10.3.1", "pointradius": 5, "points": false, "renderer": "flot", @@ -1528,7 +1876,10 @@ "steppedLine": false, "targets": [ { - "expr": "go_memstats_heap_alloc_bytes{job=\"argocd-metrics\",namespace=~\"$namespace\"}", + "datasource": { + "uid": "$datasource" + }, + "expr": "go_memstats_heap_alloc_bytes{job=\"argocd-applicationset-controller-metrics\",namespace=~\"$namespace\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "{{namespace}}", @@ -1536,9 +1887,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Memory Usage", "tooltip": { "shared": false, @@ -1547,33 +1896,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "bytes", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1581,14 +1921,23 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 7, "w": 24, "x": 0, - "y": 33 + "y": 16 }, "hiddenSeries": false, "id": 108, @@ -1612,10 +1961,11 @@ "links": [], "nullPointMode": "connected", "options": { - "dataLinks": [] + "alertThreshold": true }, "paceLength": 10, "percentage": false, + "pluginVersion": "10.3.1", "pointradius": 5, "points": false, "renderer": "flot", @@ -1625,7 +1975,10 @@ "steppedLine": false, "targets": [ { - "expr": "irate(process_cpu_seconds_total{job=\"argocd-metrics\",namespace=~\"$namespace\"}[1m])", + "datasource": { + "uid": "$datasource" + }, + "expr": "irate(process_cpu_seconds_total{job=\"argocd-applicationset-controller-metrics\",namespace=~\"$namespace\"}[1m])", "format": "time_series", "intervalFactor": 1, "legendFormat": "{{namespace}}", @@ -1633,9 +1986,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "CPU Usage", "tooltip": { "shared": false, @@ -1644,9 +1995,7 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, @@ -1654,24 +2003,17 @@ { "decimals": 1, "format": "none", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1679,14 +2021,23 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 7, "w": 24, "x": 0, - "y": 40 + "y": 23 }, "hiddenSeries": false, "id": 62, @@ -1710,10 +2061,11 @@ "links": [], "nullPointMode": "null", "options": { - "dataLinks": [] + "alertThreshold": true }, "paceLength": 10, "percentage": false, + "pluginVersion": "10.3.1", "pointradius": 5, "points": false, "renderer": "flot", @@ -1723,7 +2075,10 @@ "steppedLine": false, "targets": [ { - "expr": "go_goroutines{job=\"argocd-metrics\",namespace=~\"$namespace\"}", + "datasource": { + "uid": "$datasource" + }, + "expr": "go_goroutines{job=\"argocd-applicationset-controller-metrics\",namespace=~\"$namespace\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "{{namespace}}", @@ -1731,9 +2086,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Goroutines", "tooltip": { "shared": false, @@ -1742,42 +2095,43 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], - "title": "Controller Telemetry", + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], + "title": "AppSet Controller Telemetry", "type": "row" }, { "collapsed": true, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "gridPos": { "h": 1, "w": 24, @@ -1791,7 +2145,9 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "fillGradient": 0, "gridPos": { @@ -1832,6 +2188,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(argocd_cluster_api_resource_objects{namespace=~\"$namespace\",server=~\"$cluster\"}) by (server)", "format": "time_series", "intervalFactor": 1, @@ -1840,9 +2199,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Resource Objects Count", "tooltip": { "shared": false, @@ -1851,33 +2208,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1885,7 +2233,9 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "fillGradient": 0, "gridPos": { @@ -1927,6 +2277,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": " sum(argocd_cluster_api_resources{namespace=~\"$namespace\",server=~\"$cluster\"}) by (server)", "format": "time_series", "intervalFactor": 1, @@ -1935,9 +2288,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "API Resources Count", "tooltip": { "shared": false, @@ -1946,33 +2297,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1980,7 +2322,9 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "fillGradient": 0, "gridPos": { @@ -2021,6 +2365,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(argocd_cluster_events_total{namespace=~\"$namespace\",server=~\"$cluster\"}[$interval])) by (server)", "format": "time_series", "intervalFactor": 1, @@ -2029,9 +2376,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Cluster Events Count", "tooltip": { "shared": false, @@ -2040,42 +2385,43 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], "title": "Cluster Stats", "type": "row" }, { "collapsed": true, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "gridPos": { "h": 1, "w": 24, @@ -2089,14 +2435,23 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 0, - "y": 7 + "y": 11 }, "hiddenSeries": false, "id": 82, @@ -2114,9 +2469,10 @@ "links": [], "nullPointMode": "null", "options": { - "dataLinks": [] + "alertThreshold": true }, "percentage": false, + "pluginVersion": "10.3.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -2126,6 +2482,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(argocd_git_request_total{request_type=\"ls-remote\", namespace=~\"$namespace\"}[10m])) by (namespace)", "format": "time_series", "intervalFactor": 1, @@ -2134,9 +2493,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Git Requests (ls-remote)", "tooltip": { "shared": true, @@ -2145,33 +2502,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2179,14 +2527,23 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 12, "x": 12, - "y": 7 + "y": 11 }, "hiddenSeries": false, "id": 84, @@ -2204,9 +2561,10 @@ "links": [], "nullPointMode": "null", "options": { - "dataLinks": [] + "alertThreshold": true }, "percentage": false, + "pluginVersion": "10.3.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -2216,6 +2574,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(argocd_git_request_total{request_type=\"fetch\", namespace=~\"$namespace\"}[10m])) by (namespace)", "format": "time_series", "intervalFactor": 1, @@ -2224,9 +2585,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Git Requests (checkout)", "tooltip": { "shared": true, @@ -2235,9 +2594,7 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, @@ -2246,29 +2603,20 @@ "format": "short", "label": "", "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { - "cards": { - "cardPadding": null, - "cardRound": null - }, + "cards": {}, "color": { "cardColor": "#b4ff00", "colorScale": "sqrt", @@ -2277,12 +2625,30 @@ "mode": "spectrum" }, "dataFormat": "tsbuckets", - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + }, + "unitScale": true + }, + "overrides": [] + }, "gridPos": { "h": 8, "w": 12, "x": 0, - "y": 15 + "y": 19 }, "heatmap": {}, "hideZeroBuckets": false, @@ -2291,10 +2657,51 @@ "legend": { "show": false }, - "options": {}, + "options": { + "calculate": false, + "calculation": {}, + "cellGap": 2, + "cellValues": {}, + "color": { + "exponent": 0.5, + "fill": "#b4ff00", + "mode": "scheme", + "reverse": false, + "scale": "exponential", + "scheme": "Spectral", + "steps": 128 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "showValue": "never", + "tooltip": { + "mode": "single", + "showColorScale": false, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "short" + } + }, + "pluginVersion": "10.3.1", "reverseYBuckets": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(argocd_git_request_duration_seconds_bucket{request_type=\"fetch\", namespace=~\"$namespace\"}[$interval])) by (le)", "format": "heatmap", "intervalFactor": 10, @@ -2302,8 +2709,6 @@ "refId": "A" } ], - "timeFrom": null, - "timeShift": null, "title": "Git Fetch Performance", "tooltip": { "show": true, @@ -2313,26 +2718,15 @@ "xAxis": { "show": true }, - "xBucketNumber": null, - "xBucketSize": null, "yAxis": { - "decimals": null, "format": "short", "logBase": 1, - "max": null, - "min": null, - "show": true, - "splitFactor": null + "show": true }, - "yBucketBound": "auto", - "yBucketNumber": null, - "yBucketSize": null + "yBucketBound": "auto" }, { - "cards": { - "cardPadding": null, - "cardRound": null - }, + "cards": {}, "color": { "cardColor": "#b4ff00", "colorScale": "sqrt", @@ -2341,12 +2735,30 @@ "mode": "spectrum" }, "dataFormat": "tsbuckets", - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "scaleDistribution": { + "type": "linear" + } + }, + "unitScale": true + }, + "overrides": [] + }, "gridPos": { "h": 8, "w": 12, "x": 12, - "y": 15 + "y": 19 }, "heatmap": {}, "hideZeroBuckets": false, @@ -2355,10 +2767,51 @@ "legend": { "show": false }, - "options": {}, + "options": { + "calculate": false, + "calculation": {}, + "cellGap": 2, + "cellValues": {}, + "color": { + "exponent": 0.5, + "fill": "#b4ff00", + "mode": "scheme", + "reverse": false, + "scale": "exponential", + "scheme": "Spectral", + "steps": 128 + }, + "exemplars": { + "color": "rgba(255,0,255,0.7)" + }, + "filterValues": { + "le": 1e-9 + }, + "legend": { + "show": false + }, + "rowsFrame": { + "layout": "auto" + }, + "showValue": "never", + "tooltip": { + "mode": "single", + "showColorScale": false, + "yHistogram": false + }, + "yAxis": { + "axisPlacement": "left", + "reverse": false, + "unit": "short" + } + }, + "pluginVersion": "10.3.1", "reverseYBuckets": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(argocd_git_request_duration_seconds_bucket{request_type=\"ls-remote\", namespace=~\"$namespace\"}[$interval])) by (le)", "format": "heatmap", "intervalFactor": 10, @@ -2366,8 +2819,6 @@ "refId": "A" } ], - "timeFrom": null, - "timeShift": null, "title": "Git Ls-Remote Performance", "tooltip": { "show": true, @@ -2377,34 +2828,28 @@ "xAxis": { "show": true }, - "xBucketNumber": null, - "xBucketSize": null, "yAxis": { - "decimals": null, "format": "short", "logBase": 1, - "max": null, - "min": null, - "show": true, - "splitFactor": null + "show": true }, - "yBucketBound": "auto", - "yBucketNumber": null, - "yBucketSize": null + "yBucketBound": "auto" }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 8, "w": 24, "x": 0, - "y": 23 + "y": 27 }, "hiddenSeries": false, "id": 71, @@ -2435,7 +2880,10 @@ "steppedLine": false, "targets": [ { - "expr": "go_memstats_heap_alloc_bytes{job=\"argocd-repo-server\",namespace=~\"$namespace\"}", + "datasource": { + "uid": "$datasource" + }, + "expr": "go_memstats_heap_alloc_bytes{job=\"argocd-repo-server-metrics\",namespace=~\"$namespace\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "{{pod}}", @@ -2443,9 +2891,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Memory Used", "tooltip": { "shared": true, @@ -2454,33 +2900,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "bytes", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2488,14 +2925,16 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 7, "w": 24, "x": 0, - "y": 31 + "y": 35 }, "hiddenSeries": false, "id": 72, @@ -2526,7 +2965,10 @@ "steppedLine": false, "targets": [ { - "expr": "go_goroutines{job=\"argocd-repo-server\",namespace=~\"$namespace\"}", + "datasource": { + "uid": "$datasource" + }, + "expr": "go_goroutines{job=\"argocd-repo-server-metrics\",namespace=~\"$namespace\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "{{pod}}", @@ -2534,9 +2976,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Goroutines", "tooltip": { "shared": true, @@ -2545,42 +2985,43 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], "title": "Repo Server Stats", "type": "row" }, { "collapsed": true, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "gridPos": { "h": 1, "w": 24, @@ -2594,14 +3035,24 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "unitScale": true + }, + "overrides": [] + }, "fill": 1, + "fillGradient": 0, "gridPos": { "h": 8, "w": 24, "x": 0, - "y": 89 + "y": 12 }, + "hiddenSeries": false, "id": 61, "legend": { "avg": false, @@ -2616,8 +3067,12 @@ "linewidth": 1, "links": [], "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, "paceLength": 10, "percentage": false, + "pluginVersion": "10.3.1", "pointradius": 5, "points": false, "renderer": "flot", @@ -2627,7 +3082,10 @@ "steppedLine": false, "targets": [ { - "expr": "go_memstats_heap_alloc_bytes{job=\"argocd-server-metrics\",namespace=~\"$namespace\"}", + "datasource": { + "uid": "$datasource" + }, + "expr": "go_memstats_heap_alloc_bytes{job=\"argocd-repo-server-metrics\",namespace=~\"$namespace\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "{{pod}}", @@ -2635,9 +3093,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Memory Used", "tooltip": { "shared": true, @@ -2646,33 +3102,25 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "bytes", - "label": null, "logBase": 1, - "max": null, "min": "0", "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2680,14 +3128,24 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "unitScale": true + }, + "overrides": [] + }, "fill": 1, + "fillGradient": 0, "gridPos": { "h": 9, "w": 24, "x": 0, - "y": 97 + "y": 20 }, + "hiddenSeries": false, "id": 36, "legend": { "avg": false, @@ -2702,8 +3160,12 @@ "linewidth": 1, "links": [], "nullPointMode": "null", + "options": { + "alertThreshold": true + }, "paceLength": 10, "percentage": false, + "pluginVersion": "10.3.1", "pointradius": 5, "points": false, "renderer": "flot", @@ -2713,7 +3175,10 @@ "steppedLine": false, "targets": [ { - "expr": "go_goroutines{job=\"argocd-server-metrics\",namespace=~\"$namespace\"}", + "datasource": { + "uid": "$datasource" + }, + "expr": "go_goroutines{job=\"argocd-repo-server-metrics\",namespace=~\"$namespace\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "{{pod}}", @@ -2721,9 +3186,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Goroutines", "tooltip": { "shared": true, @@ -2732,33 +3195,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2766,14 +3220,24 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, + "fieldConfig": { + "defaults": { + "unitScale": true + }, + "overrides": [] + }, "fill": 1, + "fillGradient": 0, "gridPos": { "h": 9, "w": 24, "x": 0, - "y": 106 + "y": 29 }, + "hiddenSeries": false, "id": 38, "legend": { "avg": false, @@ -2788,8 +3252,12 @@ "linewidth": 1, "links": [], "nullPointMode": "connected", + "options": { + "alertThreshold": true + }, "paceLength": 10, "percentage": false, + "pluginVersion": "10.3.1", "pointradius": 5, "points": false, "renderer": "flot", @@ -2799,7 +3267,10 @@ "steppedLine": false, "targets": [ { - "expr": "go_gc_duration_seconds{job=\"argocd-server-metrics\", quantile=\"1\", namespace=~\"$namespace\"}", + "datasource": { + "uid": "$datasource" + }, + "expr": "go_gc_duration_seconds{job=\"argocd-repo-server-metrics\", quantile=\"1\", namespace=~\"$namespace\"}", "format": "time_series", "intervalFactor": 2, "legendFormat": "{{pod}}", @@ -2807,9 +3278,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "GC Time Quantiles", "tooltip": { "shared": true, @@ -2818,33 +3287,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2853,12 +3313,11 @@ "h": 2, "w": 24, "x": 0, - "y": 115 + "y": 38 }, "id": 54, "links": [], "mode": "markdown", - "title": "", "transparent": true, "type": "text" }, @@ -2867,14 +3326,15 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", - "decimals": null, + "datasource": { + "uid": "$datasource" + }, "fill": 1, "gridPos": { "h": 9, "w": 12, "x": 0, - "y": 117 + "y": 40 }, "id": 40, "legend": { @@ -2907,6 +3367,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"application.ApplicationService\",namespace=~\"$namespace\"}[$interval])) by (grpc_code, grpc_method)", "format": "time_series", "intervalFactor": 1, @@ -2915,9 +3378,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "ApplicationService Requests", "tooltip": { "shared": false, @@ -2926,33 +3387,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2960,13 +3412,15 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "gridPos": { "h": 9, "w": 12, "x": 12, - "y": 117 + "y": 40 }, "id": 42, "legend": { @@ -2997,6 +3451,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"cluster.ClusterService\",namespace=~\"$namespace\"}[$interval])) by (grpc_code, grpc_method)", "format": "time_series", "intervalFactor": 1, @@ -3005,9 +3462,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "ClusterService Requests", "tooltip": { "shared": false, @@ -3016,33 +3471,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3050,13 +3496,15 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "gridPos": { "h": 9, "w": 12, "x": 0, - "y": 126 + "y": 49 }, "id": 44, "legend": { @@ -3087,6 +3535,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"project.ProjectService\",namespace=~\"$namespace\"}[$interval])) by (grpc_code, grpc_method)", "format": "time_series", "intervalFactor": 1, @@ -3095,9 +3546,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "ProjectService Requests", "tooltip": { "shared": true, @@ -3106,33 +3555,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3140,13 +3580,15 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "gridPos": { "h": 9, "w": 12, "x": 12, - "y": 126 + "y": 49 }, "id": 46, "legend": { @@ -3176,6 +3618,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"repository.RepositoryService\",namespace=~\"$namespace\"}[$interval])) by (grpc_code, grpc_method)", "format": "time_series", "intervalFactor": 1, @@ -3192,9 +3637,7 @@ "yaxis": "left" } ], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "RepositoryService Requests", "tooltip": { "shared": true, @@ -3203,33 +3646,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3237,13 +3671,15 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "gridPos": { "h": 9, "w": 12, "x": 0, - "y": 135 + "y": 58 }, "id": 48, "legend": { @@ -3273,6 +3709,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"session.SessionService\",namespace=~\"$namespace\"}[$interval])) by (grpc_code, grpc_method)", "format": "time_series", "intervalFactor": 1, @@ -3281,9 +3720,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "SessionService Requests", "tooltip": { "shared": true, @@ -3292,33 +3729,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3326,13 +3754,15 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "gridPos": { "h": 9, "w": 12, "x": 12, - "y": 135 + "y": 58 }, "id": 49, "legend": { @@ -3362,6 +3792,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"version.VersionService\",namespace=~\"$namespace\"}[$interval])) by (grpc_code, grpc_method)", "format": "time_series", "intervalFactor": 1, @@ -3370,9 +3803,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "VersionService Requests", "tooltip": { "shared": true, @@ -3381,33 +3812,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3415,13 +3837,15 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "gridPos": { "h": 9, "w": 12, "x": 0, - "y": 144 + "y": 67 }, "id": 50, "legend": { @@ -3451,6 +3875,9 @@ "steppedLine": false, "targets": [ { + "datasource": { + "uid": "$datasource" + }, "expr": "sum(increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"account.AccountService\",namespace=~\"$namespace\"}[$interval])) by (grpc_code, grpc_method)", "format": "time_series", "intervalFactor": 1, @@ -3459,9 +3886,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "AccountService Requests", "tooltip": { "shared": true, @@ -3470,33 +3895,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3504,13 +3920,15 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "$datasource", + "datasource": { + "uid": "$datasource" + }, "fill": 1, "gridPos": { "h": 9, "w": 12, "x": 12, - "y": 144 + "y": 67 }, "id": 99, "legend": { @@ -3540,7 +3958,10 @@ "steppedLine": false, "targets": [ { - "expr": "sum(increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"settings.SettingsService\",namespace=~\"$namespace\"}[$interval])) by (grpc_code, grpc_method)", + "datasource": { + "uid": "$datasource" + }, + "expr": "sum(increase(grpc_server_handled_total{job=\"argocd-server-metrics\",grpc_service=\"cluster.SettingsService\",namespace=~\"$namespace\"}[$interval])) by (grpc_code, grpc_method)", "format": "time_series", "intervalFactor": 1, "legendFormat": "{{grpc_code}},{{grpc_method}}", @@ -3548,9 +3969,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "SettingsService Requests", "tooltip": { "shared": true, @@ -3559,42 +3978,44 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], + "targets": [ + { + "datasource": { + "uid": "$datasource" + }, + "refId": "A" + } + ], "title": "Server Stats", "type": "row" }, { "collapsed": true, - "datasource": null, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, "gridPos": { "h": 1, "w": 24, @@ -3608,14 +4029,24 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": null, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "links": [], + "unitScale": true + }, + "overrides": [] + }, "fill": 1, "fillGradient": 0, "gridPos": { "h": 7, "w": 24, "x": 0, - "y": 9 + "y": 13 }, "hiddenSeries": false, "id": 112, @@ -3632,9 +4063,10 @@ "linewidth": 1, "nullPointMode": "null", "options": { - "dataLinks": [] + "alertThreshold": true }, "percentage": false, + "pluginVersion": "10.3.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -3644,14 +4076,16 @@ "steppedLine": false, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, "expr": "sum(increase(argocd_redis_request_total{namespace=~\"$namespace\"}[$interval])) by (failed)", "refId": "A" } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Requests by result", "tooltip": { "shared": true, @@ -3660,58 +4094,58 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "refId": "A" + } + ], "title": "Redis Stats", "type": "row" } ], - "refresh": false, - "schemaVersion": 21, - "style": "dark", + "refresh": "", + "schemaVersion": 39, "tags": [], "templating": { "list": [ { "current": { + "selected": false, "text": "Prometheus", - "value": "Prometheus" + "value": "prometheus" }, "hide": 0, "includeAll": false, - "label": null, "multi": false, "name": "datasource", "options": [], "query": "prometheus", + "queryValue": "", "refresh": 1, "regex": "", "skipUrlSync": false, @@ -3724,11 +4158,13 @@ "text": "All", "value": "$__all" }, - "datasource": "$datasource", + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, "definition": "label_values(kube_pod_info, namespace)", "hide": 0, "includeAll": true, - "label": null, "multi": false, "name": "namespace", "options": [], @@ -3738,7 +4174,6 @@ "skipUrlSync": false, "sort": 0, "tagValuesQuery": "", - "tags": [], "tagsQuery": "", "type": "query", "useTags": false @@ -3753,7 +4188,6 @@ "value": "$__auto_interval_interval" }, "hide": 0, - "label": null, "name": "interval", "options": [ { @@ -3810,13 +4244,12 @@ { "allValue": "", "current": { - "selected": true, + "selected": false, "text": "namespace", "value": "namespace" }, "hide": 0, "includeAll": false, - "label": null, "multi": false, "name": "grouping", "options": [ @@ -3837,6 +4270,7 @@ } ], "query": "namespace,name,project", + "queryValue": "", "skipUrlSync": false, "type": "custom" }, @@ -3847,11 +4281,13 @@ "text": "All", "value": "$__all" }, - "datasource": "$datasource", + "datasource": { + "type": "prometheus", + "uid": "$datasource" + }, "definition": "label_values(argocd_cluster_info, server)", "hide": 0, "includeAll": true, - "label": null, "multi": false, "name": "cluster", "options": [], @@ -3861,7 +4297,6 @@ "skipUrlSync": false, "sort": 1, "tagValuesQuery": "", - "tags": [], "tagsQuery": "", "type": "query", "useTags": false @@ -3869,13 +4304,12 @@ { "allValue": ".*", "current": { - "selected": true, + "selected": false, "text": "All", "value": "$__all" }, "hide": 0, "includeAll": true, - "label": null, "multi": false, "name": "health_status", "options": [ @@ -3922,13 +4356,12 @@ { "allValue": ".*", "current": { - "selected": true, + "selected": false, "text": "All", "value": "$__all" }, "hide": 0, "includeAll": true, - "label": null, "multi": false, "name": "sync_status", "options": [ @@ -3991,5 +4424,6 @@ "timezone": "", "title": "ArgoCD", "uid": "LCAgc9rWz", - "version": 1 + "version": 2, + "weekStart": "" } \ No newline at end of file diff --git a/examples/k8s-rbac/argocd-server-applications/README.md b/examples/k8s-rbac/argocd-server-applications/README.md new file mode 100644 index 0000000000000..a5fc3553f68fe --- /dev/null +++ b/examples/k8s-rbac/argocd-server-applications/README.md @@ -0,0 +1,11 @@ +This folder contains example RBAC for Kubernetes to allow the Argo CD API +Server (`argocd-server`) to perform CRUD operations on `Application` CRs +in all namespaces on the cluster. + +Applying the `ClusterRole` and `ClusterRoleBinding` grant the Argo CD API +server read and write permissions cluster-wide, which may not be what you +want. Handle with care. + +Only apply these if you have installed Argo CD into the default namespace +`argocd`. Otherwise, you need to edit the cluster role binding to bind to +the service account in the correct namespace. \ No newline at end of file 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 new file mode 100644 index 0000000000000..ecbf6de3efb01 --- /dev/null +++ b/examples/k8s-rbac/argocd-server-applications/argocd-notifications-controller-rbac-clusterrole.yaml @@ -0,0 +1,28 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: argocd-notifications-controller-cluster-apps + app.kubernetes.io/part-of: argocd + app.kubernetes.io/component: notifications-controller + name: argocd-notifications-controller-cluster-apps +rules: +- apiGroups: + - "argoproj.io" + resources: + - "applications" + verbs: + - get + - list + - watch + - update + - patch +- apiGroups: + - "" + resources: + - secrets + - configmaps + verbs: + - get + - list + - watch \ No newline at end of file diff --git a/examples/k8s-rbac/argocd-server-applications/argocd-notifications-controller-rbac-clusterrolebinding.yaml b/examples/k8s-rbac/argocd-server-applications/argocd-notifications-controller-rbac-clusterrolebinding.yaml new file mode 100644 index 0000000000000..c28ab688c0716 --- /dev/null +++ b/examples/k8s-rbac/argocd-server-applications/argocd-notifications-controller-rbac-clusterrolebinding.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: argocd-notifications-controller-cluster-apps + app.kubernetes.io/part-of: argocd + app.kubernetes.io/component: notifications-controller + name: argocd-notifications-controller-cluster-apps +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: argocd-notifications-controller-cluster-apps +subjects: +- kind: ServiceAccount + name: argocd-notifications-controller + namespace: argocd diff --git a/examples/k8s-rbac/argocd-server-applications/argocd-server-rbac-clusterrole.yaml b/examples/k8s-rbac/argocd-server-applications/argocd-server-rbac-clusterrole.yaml new file mode 100644 index 0000000000000..a8d6c021c4e2e --- /dev/null +++ b/examples/k8s-rbac/argocd-server-applications/argocd-server-rbac-clusterrole.yaml @@ -0,0 +1,24 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: argocd-server-cluster-apps + app.kubernetes.io/part-of: argocd + app.kubernetes.io/component: server + name: argocd-server-cluster-apps +rules: +- apiGroups: + - "" + resources: + - events + verbs: + - create +- apiGroups: + - "argoproj.io" + resources: + - "applications" + verbs: + - create + - delete + - update + - patch diff --git a/examples/k8s-rbac/argocd-server-applications/argocd-server-rbac-clusterrolebinding.yaml b/examples/k8s-rbac/argocd-server-applications/argocd-server-rbac-clusterrolebinding.yaml new file mode 100644 index 0000000000000..1e587a3e40a31 --- /dev/null +++ b/examples/k8s-rbac/argocd-server-applications/argocd-server-rbac-clusterrolebinding.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: argocd-server-cluster-apps + app.kubernetes.io/part-of: argocd + app.kubernetes.io/component: server + name: argocd-server-cluster-apps +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: argocd-server-cluster-apps +subjects: +- kind: ServiceAccount + name: argocd-server + namespace: argocd diff --git a/examples/k8s-rbac/argocd-server-applications/kustomization.yaml b/examples/k8s-rbac/argocd-server-applications/kustomization.yaml new file mode 100644 index 0000000000000..330dde4a914d2 --- /dev/null +++ b/examples/k8s-rbac/argocd-server-applications/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: +- argocd-server-rbac-clusterrole.yaml +- argocd-server-rbac-clusterrolebinding.yaml +- argocd-notifications-controller-rbac-clusterrole.yaml +- argocd-notifications-controller-rbac-clusterrolebinding.yaml diff --git a/examples/known-hosts/kustomization.yaml b/examples/known-hosts/kustomization.yaml index 4baaf5194f6d0..ab6f0d81fd3ea 100644 --- a/examples/known-hosts/kustomization.yaml +++ b/examples/known-hosts/kustomization.yaml @@ -1,11 +1,9 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -bases: -- github.com/argoproj/argo-cd//manifests/cluster-install?ref=stable - -patchesStrategicMerge: -- argocd-known-hosts-mounts.yaml - resources: +- github.com/argoproj/argo-cd//manifests/cluster-install?ref=stable - argocd-known-hosts.yaml + +patches: +- path: argocd-known-hosts-mounts.yaml diff --git a/examples/plugins/helm/argocd-repo-server-deployment-patch.yaml b/examples/plugins/helm/argocd-repo-server-deployment-patch.yaml index aa50ec2181a9f..e933c8021a610 100644 --- a/examples/plugins/helm/argocd-repo-server-deployment-patch.yaml +++ b/examples/plugins/helm/argocd-repo-server-deployment-patch.yaml @@ -12,9 +12,9 @@ spec: - sh - -c - | - wget https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz -O - | tar xz && mv linux-amd64/helm /tools/helm && chmod +x /tools/helm + wget https://get.helm.sh/helm-v3.10.3-linux-amd64.tar.gz -O - | tar xz && mv linux-amd64/helm /tools/helm && chmod +x /tools/helm wget https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 -O /tools/jq && chmod +x /tools/jq - wget https://github.com/mikefarah/yq/releases/download/v4.24.5/yq_linux_amd64 -O /tools/yq && chmod +x /tools/yq + wget https://github.com/mikefarah/yq/releases/download/v4.30.6/yq_linux_amd64 -O /tools/yq && chmod +x /tools/yq volumeMounts: - mountPath: /tools name: helm-plugin-tools @@ -40,7 +40,7 @@ spec: subPath: generate.sh name: helm-plugin-config - mountPath: /var/run/argocd/helm-plugin/get-parameters.sh - subPath: generate.sh + subPath: get-parameters.sh name: helm-plugin-config - mountPath: /usr/local/bin name: helm-plugin-tools 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/examples/plugins/helm/kustomization.yaml b/examples/plugins/helm/kustomization.yaml index 8b6e41b71c294..78da0e841633c 100644 --- a/examples/plugins/helm/kustomization.yaml +++ b/examples/plugins/helm/kustomization.yaml @@ -1,4 +1,4 @@ -bases: +resources: - ../../../manifests/base configMapGenerator: @@ -11,5 +11,5 @@ configMapGenerator: generatorOptions: disableNameSuffixHash: true -patchesStrategicMerge: - - argocd-repo-server-deployment-patch.yaml +patches: + - path: argocd-repo-server-deployment-patch.yaml diff --git a/go.mod b/go.mod index f26a3f505bf6e..dfa17e1ce0d7d 100644 --- a/go.mod +++ b/go.mod @@ -1,240 +1,277 @@ module github.com/argoproj/argo-cd/v2 -go 1.18 +go 1.21 + +toolchain go1.21.0 require ( code.gitea.io/sdk/gitea v0.15.1 + github.com/Azure/kubelogin v0.0.20 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible - github.com/Masterminds/semver/v3 v3.2.0 + github.com/Masterminds/semver/v3 v3.2.1 + github.com/Masterminds/sprig/v3 v3.2.3 github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d - github.com/alicebob/miniredis/v2 v2.23.1 - github.com/argoproj/gitops-engine v0.7.1-0.20221208230615-917f5a0f16d5 - github.com/argoproj/notifications-engine v0.3.1-0.20221203221941-490d98afd1d6 - github.com/argoproj/pkg v0.13.7-0.20221115212233-27bd8ce31415 - github.com/aws/aws-sdk-go v1.44.164 + github.com/alicebob/miniredis/v2 v2.30.4 + github.com/antonmedv/expr v1.15.2 + 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.50.8 + github.com/bmatcuk/doublestar/v4 v4.6.0 github.com/bombsimon/logrusr/v2 v2.0.1 - github.com/bradleyfalzon/ghinstallation/v2 v2.1.0 - github.com/casbin/casbin/v2 v2.60.0 - github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect - github.com/dustin/go-humanize v1.0.0 - github.com/evanphx/json-patch v5.6.0+incompatible + 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.9.0+incompatible + github.com/felixge/httpsnoop v1.0.3 github.com/fsnotify/fsnotify v1.6.0 - github.com/ghodss/yaml v1.0.0 - github.com/go-git/go-git/v5 v5.4.2 - github.com/go-logr/logr v1.2.3 + github.com/gfleury/go-bitbucket-v1 v0.0.0-20220301131131-8e7ed04b843e + github.com/go-git/go-git/v5 v5.11.0 + github.com/go-jose/go-jose/v3 v3.0.3 + github.com/go-logr/logr v1.3.0 github.com/go-openapi/loads v0.21.2 - github.com/go-openapi/runtime v0.25.0 - github.com/go-openapi/spec v0.20.6 // indirect - github.com/go-openapi/validate v0.21.0 // indirect - github.com/go-redis/cache/v8 v8.4.2 - github.com/go-redis/redis/v8 v8.11.5 + github.com/go-openapi/runtime v0.26.0 + github.com/go-playground/webhooks/v6 v6.3.0 + github.com/go-redis/cache/v9 v9.0.0 github.com/gobwas/glob v0.2.3 - github.com/gogits/go-gogs-client v0.0.0-20190616193657-5a05380e4bc2 + github.com/gogits/go-gogs-client v0.0.0-20200905025246-8bb8a50cb355 github.com/gogo/protobuf v1.3.2 - github.com/golang-jwt/jwt/v4 v4.4.3 - github.com/golang/protobuf v1.5.2 - github.com/google/go-cmp v0.5.9 + github.com/golang-jwt/jwt/v4 v4.5.0 + github.com/golang/protobuf v1.5.3 + github.com/google/go-cmp v0.6.0 github.com/google/go-github/v35 v35.3.0 - github.com/google/go-jsonnet v0.19.1 + 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/mux v1.8.0 - github.com/gorilla/websocket v1.4.2 - github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 + github.com/gorilla/websocket v1.5.0 + github.com/gosimple/slug v1.13.1 + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/hashicorp/go-retryablehttp v0.7.0 - github.com/imdario/mergo v0.3.13 - github.com/improbable-eng/grpc-web v0.0.0-20181111100011-16092bd1d58a - github.com/itchyny/gojq v0.12.10 + github.com/hashicorp/go-retryablehttp v0.7.4 + github.com/imdario/mergo v0.3.16 + github.com/improbable-eng/grpc-web v0.15.0 + github.com/itchyny/gojq v0.12.13 github.com/jeremywohl/flatten v1.0.1 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 - github.com/ktrysmt/go-bitbucket v0.9.55 - github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8 // indirect - github.com/mattn/go-isatty v0.0.16 + github.com/ktrysmt/go-bitbucket v0.9.67 + github.com/mattn/go-isatty v0.0.19 github.com/mattn/go-zglob v0.0.4 + github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5 github.com/olekukonko/tablewriter v0.0.5 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.14.0 + github.com/prometheus/client_golang v1.16.0 github.com/r3labs/diff v1.1.0 - github.com/rs/cors v1.8.0 // indirect - github.com/sirupsen/logrus v1.9.0 + github.com/redis/go-redis/v9 v9.0.5 + github.com/robfig/cron/v3 v3.0.1 + github.com/sirupsen/logrus v1.9.3 github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c github.com/soheilhy/cmux v0.1.5 - github.com/spf13/cobra v1.6.1 + github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.4 github.com/valyala/fasttemplate v1.2.2 - github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0 - github.com/xanzy/go-gitlab v0.60.0 - github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa - golang.org/x/net v0.4.0 // indirect - golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 - golang.org/x/term v0.3.0 - google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90 - google.golang.org/grpc v1.51.0 - google.golang.org/protobuf v1.28.1 - gopkg.in/go-playground/webhooks.v5 v5.17.0 + github.com/whilp/git-urls v1.0.0 + 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.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.19.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.17.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/yaml.v2 v2.4.0 - k8s.io/api v0.24.2 - k8s.io/apiextensions-apiserver v0.24.2 - k8s.io/apimachinery 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-20220210201930-3a6ce19ff2f9 + gopkg.in/yaml.v3 v3.0.1 + k8s.io/api v0.26.11 + k8s.io/apiextensions-apiserver v0.26.10 + 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 - sigs.k8s.io/controller-runtime v0.11.0 - sigs.k8s.io/structured-merge-diff/v4 v4.2.3 + oras.land/oras-go/v2 v2.3.0 + sigs.k8s.io/controller-runtime v0.14.7 + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 sigs.k8s.io/yaml v1.3.0 ) require ( - github.com/gfleury/go-bitbucket-v1 v0.0.0-20220301131131-8e7ed04b843e - github.com/stretchr/objx v0.5.0 // indirect - gopkg.in/square/go-jose.v2 v2.6.0 // indirect - k8s.io/apiserver v0.24.2 + dario.cat/mergo v1.0.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1 // indirect + 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.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 + 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 ( - github.com/Masterminds/sprig/v3 v3.2.2 - github.com/antonmedv/expr v1.9.0 - github.com/coreos/go-oidc/v3 v3.4.0 - github.com/gosimple/slug v1.13.1 - github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5 - github.com/robfig/cron/v3 v3.0.1 - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.31.0 - go.opentelemetry.io/otel v1.11.1 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1 - go.opentelemetry.io/otel/sdk v1.11.1 -) - -require ( - github.com/emicklei/go-restful/v3 v3.8.0 // indirect - github.com/google/go-github/v45 v45.2.0 // indirect - github.com/rivo/uniseg v0.2.0 // indirect - github.com/shopspring/decimal v1.2.0 // indirect - github.com/spf13/cast v1.4.1 // indirect -) - -require ( - cloud.google.com/go/compute v1.7.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 - github.com/Azure/go-autorest/autorest v0.11.18 // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect + github.com/Azure/go-autorest/autorest v0.11.27 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.20 // indirect 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/Masterminds/semver v1.5.0 // indirect - github.com/Masterminds/sprig v2.22.0+incompatible // indirect - github.com/Microsoft/go-winio v0.4.17 // indirect - github.com/PagerDuty/go-pagerduty v1.6.0 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // 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-20230828082145-3c4c8a2d2371 // indirect github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 // indirect - github.com/acomagu/bufpipe v1.0.3 // indirect github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect - github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.1.3 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/cenkalti/backoff/v4 v4.2.1 // 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.1+incompatible // indirect - github.com/emirpasic/gods v1.12.0 // indirect + github.com/docker/distribution v2.8.2+incompatible // 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/form3tech-oss/jwt-go v3.2.3+incompatible // indirect github.com/fvbommel/sortorder v1.0.1 // indirect - github.com/go-errors/errors v1.0.1 // indirect - github.com/go-git/gcfg v1.5.0 // indirect - github.com/go-git/go-billy/v5 v5.3.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.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.2 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.20.0 // indirect - github.com/go-openapi/strfmt v0.21.3 // indirect - github.com/go-openapi/swag v0.21.1 // indirect + github.com/go-openapi/errors v0.20.3 // 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.0.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.0.1 // indirect - github.com/google/gnostic v0.5.7-v3refs // indirect + github.com/google/btree v1.1.2 // indirect + github.com/google/gnostic v0.6.9 // indirect github.com/google/go-github/v41 v41.0.0 // indirect + github.com/google/go-github/v53 v53.2.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/gofuzz v1.1.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect github.com/gosimple/unidecode v1.0.1 // indirect - github.com/gregdel/pushover v1.1.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // 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.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.1 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/huandu/xstrings v1.3.3 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/itchyny/timefmt-go v0.1.5 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jonboulle/clockwork v0.2.2 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect - github.com/klauspost/compress v1.15.9 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/compress v1.16.5 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect - github.com/mitchellh/mapstructure v1.4.3 // indirect + 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 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc4 // indirect github.com/opsgenie/opsgenie-go-sdk-v2 v1.0.5 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + 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/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect - github.com/russross/blackfriday v1.5.2 // 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.9.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect - github.com/slack-go/slack v0.10.1 // indirect + github.com/shopspring/decimal 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 github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/vmihailenco/go-tinylfu v0.2.1 // indirect + github.com/vmihailenco/go-tinylfu v0.2.2 // indirect github.com/vmihailenco/msgpack/v5 v5.3.4 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/xanzy/ssh-agent v0.3.0 // indirect - github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect - go.mongodb.org/mongo-driver v1.10.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1 // indirect - go.opentelemetry.io/otel/trace v1.11.1 // indirect - go.opentelemetry.io/proto/otlp v0.19.0 // indirect - go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect - golang.org/x/exp v0.0.0-20210901193431-a062eea981d2 // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect - golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect - golang.org/x/tools v0.1.12 // indirect + 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/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.12.0 // indirect + golang.org/x/net v0.19.0 + golang.org/x/sys v0.17.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 @@ -243,16 +280,15 @@ 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 - gopkg.in/yaml.v3 v3.0.1 // 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-20211208200746-9f7c6b3444d2 // indirect - sigs.k8s.io/kustomize/api v0.11.4 // indirect - sigs.k8s.io/kustomize/kyaml v0.13.6 // 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 ( @@ -261,35 +297,41 @@ replace ( github.com/golang/protobuf => github.com/golang/protobuf v1.4.2 github.com/grpc-ecosystem/grpc-gateway => github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/improbable-eng/grpc-web => github.com/improbable-eng/grpc-web v0.0.0-20181111100011-16092bd1d58a + + // Avoid CVE-2022-3064 + gopkg.in/yaml.v2 => gopkg.in/yaml.v2 v2.4.0 // 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 d67a1250468cf..d2e8f3c56535a 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,9 @@ -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= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= @@ -17,6 +16,7 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= @@ -28,94 +28,637 @@ cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+Y cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= +cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= +cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= +cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= +cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= +cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= +cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= +cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= +cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= +cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= +cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= +cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= +cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= +cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= +cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= +cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= +cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= +cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= +cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= +cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= +cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= +cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= +cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= +cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= +cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= +cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= +cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= +cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= +cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= +cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= +cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= +cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= +cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= +cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= +cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= +cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= +cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= +cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= +cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= +cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= +cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= +cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= +cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= +cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= +cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= +cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= +cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= +cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= +cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= +cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= +cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= +cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= +cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= +cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= +cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= +cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= +cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= +cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= +cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= +cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= +cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= +cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= +cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= +cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= +cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= +cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= +cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= +cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= +cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= +cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= +cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= +cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= +cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= +cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= +cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= +cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= +cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= +cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= +cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= +cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= +cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= +cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= +cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= +cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= +cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= +cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= +cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= +cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= +cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= +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.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= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= +cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= +cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= +cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= +cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= +cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= +cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= +cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= +cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= +cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= +cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= +cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= +cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= +cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= +cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= +cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= +cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= +cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= +cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= +cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= +cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= +cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= +cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= +cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= +cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= +cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= +cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= +cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= +cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= +cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= +cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= +cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= +cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= +cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= +cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= +cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= +cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= +cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= +cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= +cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= +cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= +cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= +cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= +cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= +cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= +cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= +cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= +cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= +cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= +cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= +cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= +cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= +cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= +cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= +cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= +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.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= +cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= +cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= +cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= +cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= +cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= +cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= +cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= +cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= +cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= +cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= +cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= +cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= +cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= +cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= +cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= +cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= +cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= +cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= +cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= +cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= +cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= +cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= +cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= +cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= +cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= +cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= +cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= +cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= +cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= +cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= +cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= +cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= +cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= +cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= +cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= +cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= +cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= +cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= +cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= +cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= +cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= +cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= +cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= +cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= +cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= +cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= +cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= +cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= +cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= +cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= +cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= +cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= +cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= +cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= +cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= +cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= +cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= +cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= +cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= +cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= +cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= +cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= +cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= +cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= +cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= +cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= +cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= +cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= +cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= +cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= +cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= +cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= +cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= +cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= +cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= +cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= +cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= +cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= +cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= +cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= +cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= +cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= +cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= +cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= +cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= +cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= +cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= +cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= +cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= +cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= +cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= +cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= +cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= +cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= +cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= +cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= +cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= +cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= +cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= +cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= +cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= +cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= +cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= +cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= +cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= +cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= +cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= +cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= +cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= +cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= +cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= +cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= +cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= +cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= +cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= +cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= +cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= +cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= +cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= +cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= +cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= +cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= +cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= +cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= +cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= +cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= +cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= +cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= +cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= +cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= +cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= +cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= +cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= +cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= +cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= +cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= +cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= +cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= +cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= +cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= +cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= +cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= +cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= +cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= +cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= +cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= +cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= +cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= +cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= +cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= +cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= +cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= +cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= +cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= +cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= +cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= +cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= +cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= +cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= +cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= +cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= +cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= +cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= +cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= +cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= +cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= +cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= +cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= +cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= +cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= +cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= +cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= +cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= +cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= +cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= +cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= +cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= +cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= +cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= +cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= +cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= +cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= +cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= +cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= +cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= +cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= +cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= +cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= +cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= +cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= +cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= +cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= +cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= +cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= +cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= +cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= +cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= +cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= +cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= +cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= +cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= +cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= +cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= +cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= +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= -github.com/Azure/azure-sdk-for-go v55.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +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/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= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0/go.mod h1:bhXu1AjYL+wutSL/kpSq6s7733q2Rb0yuot9Zgfqa/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= 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 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= -github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= -github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +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.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= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -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/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/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= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/Azure/kubelogin v0.0.20 h1:pDJhxzUWk2f/wjYQJFb0Vet7OYrcg6DLx1qj+sbXY70= +github.com/Azure/kubelogin v0.0.20/go.mod h1:QNuYUuwM2lqho9ovG5U/yv3/ZmFbEru3Jluw2ZeKcSk= +github.com/AzureAD/microsoft-authentication-library-for-go v0.5.2 h1:BGX4OiGP9htYSd6M3pAZctcUUSruhIAUVkv2X0Cn9yE= +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/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= -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 v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= -github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= -github.com/Microsoft/go-winio v0.4.17 h1:iT12IBVClFevaf8PuVyi3UmZOVh4OqnaLxDTW2O6j3w= -github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +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.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/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.6.0 h1:am81SzvG5Pw+s3JZ5yEy6kGvsXXklTNRrGr3d8WKpsU= -github.com/PagerDuty/go-pagerduty v1.6.0/go.mod h1:7eaBLzsDpK7VUvU0SJ5mohczQkoWrrr5CjDaw5gh1as= -github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ= -github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +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-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= @@ -125,10 +668,11 @@ 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.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= -github.com/acomagu/bufpipe v1.0.3/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= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -136,25 +680,27 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk= github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis/v2 v2.23.1 h1:jR6wZggBxwWygeXcdNyguCOCIjPsZyNUNlAkTx2fu0U= -github.com/alicebob/miniredis/v2 v2.23.1/go.mod h1:84TWKZlxYkfgMucPBf5SOQBYJceZeQRFIaQgNMiCX6Q= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOSchFS7Eo= +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.9.0 h1:j4HI3NHEdgDnN9p6oI6Ndr0G5QryMY0FNxT4ONrFDGU= -github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8= +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.20221208230615-917f5a0f16d5 h1:iRpHi7X3q9G55KTaMjxKicgNnS2blFHaEfOOgsmP8lE= -github.com/argoproj/gitops-engine v0.7.1-0.20221208230615-917f5a0f16d5/go.mod h1:WpA/B7tgwfz+sdNE3LqrTrb7ArEY1FOPI2pAGI0hfPc= -github.com/argoproj/notifications-engine v0.3.1-0.20221203221941-490d98afd1d6 h1:b92Xft7MQv/SP56FW08zt5CMTE1rySH8UPDKOAgSzOM= -github.com/argoproj/notifications-engine v0.3.1-0.20221203221941-490d98afd1d6/go.mod h1:pgPU59KCsBOMhyw9amRWPoSuBmUWvx3Xsc5r0mUriLg= -github.com/argoproj/pkg v0.13.7-0.20221115212233-27bd8ce31415 h1:/5UtDHntvwPxbe/j2+xmQgvG83PQueGHko+9sf8+FA0= -github.com/argoproj/pkg v0.13.7-0.20221115212233-27bd8ce31415/go.mod h1:vqTRUU8ATWVtKog5bVg0zDrKxEjUaFnObZaqpY0oprQ= +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= @@ -162,148 +708,155 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/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/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/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.129/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go v1.44.164 h1:qDj0RutF2Ut0HZYyUJxFdReLxpYrjupsu2JmDIgCvX8= -github.com/aws/aws-sdk-go v1.44.164/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.289/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.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/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +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/bombsimon/logrusr/v2 v2.0.1 h1:1VgxVNQMCvjirZIYaT9JYn6sAVGVEcNtRE0y4mvaOAM= github.com/bombsimon/logrusr/v2 v2.0.1/go.mod h1:ByVAX+vHdLGAfdroiMg6q0zgq2FODY2lc5YJvzmOJio= -github.com/bradleyfalzon/ghinstallation/v2 v2.1.0 h1:5+NghM1Zred9Z078QEZtm28G/kfDfZN/92gkDlLwGVA= -github.com/bradleyfalzon/ghinstallation/v2 v2.1.0/go.mod h1:Xg3xPRN5Mcq6GDqeUVhFbjEWMb4JHCyWEeeBGEYQoTU= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +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= github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= -github.com/casbin/casbin/v2 v2.60.0 h1:ZmC0/t4wolfEsDpDxTEsu2z6dfbMNpc11F52ceLs2Eo= -github.com/casbin/casbin/v2 v2.60.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= +github.com/casbin/casbin/v2 v2.77.2 h1:yQinn/w9x8AswiwqwtrXz93VU48R1aYTXdHEx4RI3jM= +github.com/casbin/casbin/v2 v2.77.2/go.mod h1:mzGx0hYW9/ksOSpw3wNjk3NRAroq5VMFYUQ6G43iGPk= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= -github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -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/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/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 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/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/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 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/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= +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/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= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +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.4.0 h1:xz7elHb/LDwm/ERpwHd+5nb7wFHL32rsr6bBOgaeu6g= -github.com/coreos/go-oidc/v3 v3.4.0/go.mod h1:eHUXhZtXPQLgEaDrOVTgwbgmz1xGOkJNye6h3zkD2Pw= +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/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= -github.com/docker/distribution v2.8.1+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/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= +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/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 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= 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 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -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/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +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= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -314,13 +867,20 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= +github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +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/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/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= @@ -329,113 +889,127 @@ github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+ne github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 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/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/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 h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= 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.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= +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/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= -github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= -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/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= -github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8= -github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= -github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= -github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +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/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= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +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.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.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= +github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-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= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.0.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 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 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/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= github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.2 h1:dxy7PGTqEh94zj2E3h1cUmQQWiM1+aeCROfAr02EmK8= github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= +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= -github.com/go-openapi/runtime v0.25.0 h1:7yQTCdRbWhX8vnIjdzU8S00tBYf7Sg71EBeorlPHvhc= -github.com/go-openapi/runtime v0.25.0/go.mod h1:Ux6fikcHXyyob6LNWxtE96hWwjBPYF0DXgVFuMTneOs= +github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc= +github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ= github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= -github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ= github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.20.8 h1:ubHmXNY3FCIOinT8RNrrPfGc9t7I1qhPtdOGoG2AxRU= +github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= +github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k= +github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/validate v0.21.0 h1:+Wqk39yKOhfpLqNLEC0/eViCkzM5FVXVqrvt526+wcI= -github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= -github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= -github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= -github.com/go-redis/cache/v8 v8.4.2 h1:8YbsmnU1Ws3TKS6T+qALzYE/MlGE+A/lrlx1XTA3p6M= -github.com/go-redis/cache/v8 v8.4.2/go.mod h1:X7Jjd69Ssbrf3xBQLtIDE0g3WcSbFoQiSGeb8QfEJ+g= -github.com/go-redis/redis/v8 v8.11.3/go.mod h1:xNJ9xDG09FsIPwh3bWdk+0oDWHbtF9rPN0F/oD9XeKc= -github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= -github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= +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-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.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.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= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/webhooks/v6 v6.3.0 h1:zBLUxK1Scxwi97TmZt5j/B/rLlard2zY7P77FHg58FE= +github.com/go-playground/webhooks/v6 v6.3.0/go.mod h1:GCocmfMtpJdkEOM1uG9p2nXzg1kY5X/LtvQgtPHUaaA= +github.com/go-redis/cache/v9 v9.0.0 h1:0thdtFo0xJi0/WXbRVu8B066z8OvVymXTJGaXrVWnN0= +github.com/go-redis/cache/v9 v9.0.0/go.mod h1:cMwi1N8ASBOufbIvk7cdXe2PbPjK/WMRL95FFHWsSgI= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -469,26 +1043,34 @@ github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/V github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/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-20190616193657-5a05380e4bc2 h1:BbwX8wsMRDZRdNYxAna+4ls3wvMKJyn4PT6Zk1CPxP4= -github.com/gogits/go-gogs-client v0.0.0-20190616193657-5a05380e4bc2/go.mod h1:cY2AIrMgHm6oOHmR7jY+9TtjzSjQ3iG7tURJG3Y6XH0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= +github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +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/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/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU= -github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= 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 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +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= @@ -511,17 +1093,18 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 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 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= -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/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= +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/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= +github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -535,26 +1118,29 @@ 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= github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= -github.com/google/go-github/v45 v45.2.0 h1:5oRLszbrkvxDDqBCNj2hjDZMKmvexaZ1xw/FCD+K3FI= -github.com/google/go-github/v45 v45.2.0/go.mod h1:FObaZJEDSTa/WGCzZ2Z3eoCDXWJKMenWWTrd8jrta28= -github.com/google/go-jsonnet v0.19.1 h1:MORxkrG0elylUqh36R4AcSPX0oZQa9hvI3lroN+kDhs= -github.com/google/go-jsonnet v0.19.1/go.mod h1:5JVT33JVCoehdTj5Z2KJq1eIdt3Nb8PCmZ+W5D8U350= +github.com/google/go-github/v53 v53.2.0 h1:wvz3FyF53v4BK+AsnvCmeNhf8AkTaeh2SoYu/XUvTtI= +github.com/google/go-github/v53 v53.2.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSXGt7mOsAWEloao= +github.com/google/go-jsonnet v0.20.0 h1:WG4TTSARuV7bSm4PMB4ohjxe33IHT5WVTrJSU33uT4g= +github.com/google/go-jsonnet v0.20.0/go.mod h1:VbgWF9JX7ztlv770x/TolZNGGFfiHEVx9G6ca2eUmeA= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -564,20 +1150,33 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 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= @@ -585,47 +1184,53 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0 github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= +github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +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/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 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -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.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosimple/slug v1.13.1 h1:bQ+kpX9Qa6tHRaK+fZR0A0M2Kd7Pa5eHPPsb1JpHD+Q= github.com/gosimple/slug v1.13.1/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= -github.com/gregdel/pushover v1.1.0 h1:dwHyvrcpZCOS9V1fAnKPaGRRI5OC55cVaKhMybqNsKQ= -github.com/gregdel/pushover v1.1.0/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to= +github.com/gregdel/pushover v1.2.1 h1:IPPJCdzXz60gMqnlzS0ZAW5z5aS1gI4nU+YM0Pe+ssA= +github.com/gregdel/pushover v1.2.1/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to= 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.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= +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= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 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 h1:BZHcxBETFHIdVyhyEfOvn/RdU/QGdLI4y34qQGjGWO0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= +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= @@ -638,8 +1243,8 @@ github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-retryablehttp v0.5.1/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= -github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= +github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= @@ -651,34 +1256,30 @@ 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.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +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.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/improbable-eng/grpc-web v0.0.0-20181111100011-16092bd1d58a h1:RweVA0vnEyStwtAelyGmnU8ENDnwd1Q7pQr7U3J/rXo= -github.com/improbable-eng/grpc-web v0.0.0-20181111100011-16092bd1d58a/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= +github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +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.10 h1:6TcS0VYWS6wgntpF/4tnrzwdCMjiTxRAxIqZWfDsDQU= -github.com/itchyny/gojq v0.12.10/go.mod h1:o3FT8Gkbg/geT4pLI0tF3hvip5F3Y/uskjRz9OYa38g= +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= github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk= @@ -687,7 +1288,6 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i github.com/jeremywohl/flatten v1.0.1 h1:LrsxmB3hfwJuE+ptGOijix1PIfOoKLJ3Uee/mzbgtrs= github.com/jeremywohl/flatten v1.0.1/go.mod h1:4AmD/VxjWcI5SRB0n6szE2A6s2fsNHDLO0nAlMHgfLQ= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -703,8 +1303,8 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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= @@ -712,27 +1312,30 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= 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 v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +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/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= +github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -740,34 +1343,33 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/ktrysmt/go-bitbucket v0.9.55 h1:eOrF7wWmG4wz5iPr7ymgyWLoti2OfmrhU2tmT6yhAu8= -github.com/ktrysmt/go-bitbucket v0.9.55/go.mod h1:y5wrrDHCGUFAtuC43GyLBeFigq7rwrh4HqeDOOyZT+A= -github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= -github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= +github.com/ktrysmt/go-bitbucket v0.9.67 h1:pFQs95TTgrwd3I9gKnas8zTYMVUOId0ZI4N0yqqMEVQ= +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.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 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/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= -github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= 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= @@ -775,65 +1377,55 @@ 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-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 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 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= 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.8/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= +github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 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 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= -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.43/go.mod h1:nCrRzjoSUQh8hgKKtu3Y708OLvRLtuASMg2/nvmbarw= -github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= -github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +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/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 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -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= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +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= @@ -841,20 +1433,18 @@ 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/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= 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= +github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= @@ -874,38 +1464,46 @@ 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= -github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= +github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= +github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0= +github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo= +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 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= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= -github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= +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/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/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/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/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= @@ -921,35 +1519,39 @@ 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= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= +github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= 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.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +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= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -958,59 +1560,55 @@ 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.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.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= +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.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.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -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/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +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/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/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= -github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84= -github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +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-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= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= +github.com/rogpeppe/clock v0.0.0-20190514195947-2896927a307a h1:3QH7VyOaaiUHNrA9Se4YQIRkDTCw1EJls9xTUCaCeRM= +github.com/rogpeppe/clock v0.0.0-20190514195947-2896927a307a/go.mod h1:4r5QyqhjIWCcK8DO4KMclc5Iknq5qVBAlbYYzAbUScQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 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/rs/cors v1.8.0 h1:P2KMzcFwrPoSjkF1WLRPsp3UMLyql8L4v9hQpVeK5so= -github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= -github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +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.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/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= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= 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/sanity-io/litter v1.2.0/go.mod h1:JF6pZUFgu2Q0sBZ+HSV35P8TVPI1TTzEwyu9FXAw2W4= 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= @@ -1023,14 +1621,16 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +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.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.10.1 h1:BGbxa0kMsGEvLOEoZmYs8T1wWfoZXwmQFBb6FgYCXUA= -github.com/slack-go/slack v0.10.1/go.mod h1:wWL//kk0ho+FcQXcBTmEafUI5dz4qz5f4mMk8oIkioQ= +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= @@ -1040,43 +1640,30 @@ 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/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= -github.com/spf13/cast v1.4.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.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= -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/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= 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= -github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1085,51 +1672,50 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -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/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +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/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= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +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.1 h1:78/wH+STtgM8+fN2GdjvvKoxF3mkdzoOoKQTchQRj+g= -github.com/vmihailenco/go-tinylfu v0.2.1/go.mod h1:CutYi2Q9puTxfcolkliPq4npPuofg9N9t8JVrjzwa3Q= +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 v0.0.0-20191001220047-6db9661140c0 h1:qqllXPzXh+So+mmANlX/gCJrgo+1kQyshMoQ+NASzm0= -github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0/go.mod h1:2rx5KE5FLD0HRfkkpyn8JwbVLBdhgeiOb2D2D9LLKM4= -github.com/xanzy/go-gitlab v0.60.0 h1:HaIlc14k4t9eJjAhY0Gmq2fBHgKd1MthBn3+vzDtsbA= -github.com/xanzy/go-gitlab v0.60.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM= -github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= -github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +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= +github.com/xanzy/go-gitlab v0.91.1/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +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 h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= -github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +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/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= @@ -1138,26 +1724,17 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ= -github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +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.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 h1:UtV6N5k14upNp4LTduX0QCufG124fSu25Wz9tu94GLg= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= +go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= +go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -1167,63 +1744,50 @@ 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.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.31.0 h1:li8u9OSMvLau7rMs8bmiL82OazG6MAkwPz2i6eS8TBQ= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.31.0/go.mod h1:SY9qHHUES6W3oZnO1H2W8NvsSovIoXRg/A1AH9px8+I= -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.6.1/go.mod h1:blzUabWHkX6LJewxvadmzafgh/wnvBSDBdOuwkAtrWQ= -go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= -go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= -go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 h1:X2GndnMCsUPh6CiY2a+frAbNsXaPLbB0soHRYhAZ5Ig= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1/go.mod h1:i8vjiSzbiUC7wOQplijSXMYUpNM93DtlS5CbUT+C6oQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1 h1:MEQNafcNCB0uQIti/oHgU7CZpUMYQ7qigBwMVKycHvc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.11.1/go.mod h1:19O5I2U5iys38SsmT2uDJja/300woyzE1KPIQxEUBUc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1 h1:LYyG/f1W/jzAix16jbksJfMQFpOH/Ma6T639pVPMgfI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.11.1/go.mod h1:QrRRQiY3kzAoYPNLP0W/Ikg0gR6V3LMc+ODSxr7yyvg= -go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -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.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs= -go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys= -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.6.1/go.mod h1:RkFRM1m0puWIq10oxImnGEduNBzxiN7TXluRBtE+5j0= -go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= -go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= +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/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/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.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= +go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= -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= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.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.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= +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.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 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.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -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.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +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-20190219172222-a4c6cb3142f2/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= @@ -1233,38 +1797,56 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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-20200414173820-0848c9571904/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-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 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-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +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-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.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +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/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= 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= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20210220032938-85be41e4509f/go.mod h1:I6l2HNBLBZEcrOoCpyKLdY2lHoRZ8lI4x60KMCQDft4= -golang.org/x/exp v0.0.0-20210901193431-a062eea981d2 h1:Or4Ra3AAlhUlNn8WmIzw2Yq2vUHSkrP6E2e/FIESpF8= -golang.org/x/exp v0.0.0-20210901193431-a062eea981d2/go.mod h1:a3o/VtDNHN+dCVLEpzjjUHOzR+Ln3DHX056ZPzoZGGA= +golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +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= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1279,23 +1861,25 @@ 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= -golang.org/x/mod v0.5.1-0.20210830214625-1b1db11ec8f4/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +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/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= @@ -1309,7 +1893,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= @@ -1325,6 +1908,7 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -1343,13 +1927,12 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 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-20210825183410-e898025ed96a/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-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= @@ -1358,13 +1941,28 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +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/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= @@ -1376,8 +1974,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= @@ -1387,8 +1983,18 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 h1:2o1E+E8TpNLklK9nHiPiK1uzIYrIHt+cQx3ynCwq9V8= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= +golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= +golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= +golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1402,20 +2008,22 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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= @@ -1427,20 +2035,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-20190626150813-e07cf5db2756/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= @@ -1448,15 +2049,14 @@ 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= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1466,8 +2066,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= @@ -1476,60 +2074,84 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/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= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220406155245-289d7a0edf71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +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/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.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= -golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +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/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= 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= @@ -1539,21 +2161,30 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +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/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 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= -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= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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= @@ -1574,11 +2205,11 @@ golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 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= @@ -1587,7 +2218,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= @@ -1611,20 +2241,29 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 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.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +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/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= @@ -1632,6 +2271,7 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45 h1:juzzlx91nWAOsHuOVfXZPMXHtJEKouZvY9bBbwlOeYs= gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45/go.mod h1:41y72mzHT7+jFNgyBpJRrZWuZJcLmLrTpq6iGgOFJMQ= gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= @@ -1640,11 +2280,13 @@ 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= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -1667,8 +2309,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= @@ -1684,10 +2324,33 @@ google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/S google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= +google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= +google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= +google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= +google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= +google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= +google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= +google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjYK+5E= +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= @@ -1711,7 +2374,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= @@ -1732,18 +2394,19 @@ 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= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 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= @@ -1772,17 +2435,86 @@ google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2 google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90 h1:4SPz2GL2CXJt28MTF8V6Ap/9ZiVbQlJeGSd9qtA7DLs= google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= +google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= +google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= +google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= +google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= +google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= +google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= +google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= +google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= +google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= +google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +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-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-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-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= @@ -1801,6 +2533,7 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= @@ -1820,20 +2553,31 @@ google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11 google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= +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.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= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= @@ -1846,36 +2590,18 @@ 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/go-playground/webhooks.v5 v5.17.0 h1:truBced5ZmkiNKK47cM8bMe86wUSjNks7SFMuNKwzlc= -gopkg.in/go-playground/webhooks.v5 v5.17.0/go.mod h1:LZbya/qLVdbqDR1aKrGuWV6qbia2zCYSR5dpom2SInQ= 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.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -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/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +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/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.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -1892,90 +2618,105 @@ 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-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 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/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= -modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= -modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= -modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= -modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= -modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +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/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= +modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= +modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= +modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= +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/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= +modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= +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.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= +modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= +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.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/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= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +oras.land/oras-go/v2 v2.3.0 h1:lqX1aXdN+DAmDTKjiDyvq85cIaI4RkIKp/PghWlAGIU= +oras.land/oras-go/v2 v2.3.0/go.mod h1:GeAwLuC4G/JpNwkd+bSZ6SkDMGaaYglt6YK2WvZP7uQ= 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 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y= -sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= -sigs.k8s.io/kustomize/api v0.11.4 h1:/0Mr3kfBBNcNPOW5Qwk/3eb8zkswCwnqQxxKtmrTkRo= -sigs.k8s.io/kustomize/api v0.11.4/go.mod h1:k+8RsqYbgpkIrJ4p9jcdPqe8DprLxFUUO0yNOq8C+xI= -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 h1:eF+wsn4J7GOAXlvajv6OknSunxpcOBQQqsnPxObtkGs= -sigs.k8s.io/kustomize/kyaml v0.13.6/go.mod h1:yHP031rn1QX1lr/Xd934Ri/xdVNG8BE2ECa78Ht/kEg= -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.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= +sigs.k8s.io/controller-runtime v0.14.7 h1:Vrnm2vk9ZFlRkXATHz0W0wXcqNl7kPat8q2JyxVy0Q8= +sigs.k8s.io/controller-runtime v0.14.7/go.mod h1:ErTs3SJCOujNUnTz4AS+uh8hp6DHMo1gj6fFndJT1X8= +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-catalog/main.go b/hack/gen-catalog/main.go index 05f27406a9a25..486327e33ee6e 100644 --- a/hack/gen-catalog/main.go +++ b/hack/gen-catalog/main.go @@ -16,12 +16,12 @@ import ( "github.com/argoproj/notifications-engine/pkg/services" "github.com/argoproj/notifications-engine/pkg/triggers" "github.com/argoproj/notifications-engine/pkg/util/misc" - "github.com/ghodss/yaml" "github.com/olekukonko/tablewriter" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/yaml" ) func main() { @@ -150,7 +150,7 @@ func generateBuiltInTriggersDocs(out io.Writer, triggers map[string][]triggers.C } func generateCommandsDocs(out io.Writer) error { - // create parents so that CommandPath() is correctly resolved + // create parents so that CommandPath() is correctly resolved mainCmd := &cobra.Command{Use: "argocd"} adminCmd := &cobra.Command{Use: "admin"} toolCmd := admin.NewNotificationsCommand() diff --git a/hack/gen-crd-spec/main.go b/hack/gen-crd-spec/main.go index f69e3b17e7534..e7dcd658ef26a 100644 --- a/hack/gen-crd-spec/main.go +++ b/hack/gen-crd-spec/main.go @@ -10,9 +10,9 @@ import ( "github.com/argoproj/argo-cd/v2/pkg/apis/application" "github.com/argoproj/gitops-engine/pkg/utils/kube" - "github.com/ghodss/yaml" extensionsobj "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "sigs.k8s.io/yaml" ) var ( diff --git a/hack/gen-docs/main.go b/hack/gen-docs/main.go index 180b02fffec4f..b076224a0aaee 100644 --- a/hack/gen-docs/main.go +++ b/hack/gen-docs/main.go @@ -25,7 +25,7 @@ func generateNotificationsDocs() { log.Fatal(err) } if files != nil { - if e := updateMkDocsNav("Operator Manual", "Notification", "Notification Services", files); e != nil { + if e := updateMkDocsNav("Operator Manual", "Notifications", "Notification Services", files); e != nil { log.Fatal(e) } } @@ -49,6 +49,9 @@ func updateMkDocsNav(parent string, child string, subchild string, files []strin } rootnavitemmap := rootitem.(map[interface{}]interface{}) childnav, _ := findNavItem(rootnavitemmap[parent].([]interface{}), child) + if childnav == nil { + return fmt.Errorf("Can't find '%s' chile item under '%s' parent item in mkdoc.yml", child, parent) + } childnavmap := childnav.(map[interface{}]interface{}) childnavitems := childnavmap[child].([]interface{}) diff --git a/hack/gen-resources/generators/application_generator.go b/hack/gen-resources/generators/application_generator.go index b19280ae688b9..9e78299d979b0 100644 --- a/hack/gen-resources/generators/application_generator.go +++ b/hack/gen-resources/generators/application_generator.go @@ -31,8 +31,8 @@ func NewApplicationGenerator(argoClientSet *appclientset.Clientset, clientSet *k } func (pg *ApplicationGenerator) buildRandomSource(repositories []*v1alpha1.Repository) (*v1alpha1.ApplicationSource, error) { - rand.Seed(time.Now().Unix()) - repoNumber := rand.Int() % len(repositories) + seed := rand.New(rand.NewSource(time.Now().Unix())) + repoNumber := seed.Int() % len(repositories) return &v1alpha1.ApplicationSource{ RepoURL: repositories[repoNumber].Repo, Path: "helm-guestbook", @@ -49,8 +49,8 @@ func (ag *ApplicationGenerator) buildSource(opts *util.GenerateOpts, repositorie } func (pg *ApplicationGenerator) buildRandomDestination(opts *util.GenerateOpts, clusters []v1alpha1.Cluster) (*v1alpha1.ApplicationDestination, error) { - rand.Seed(time.Now().Unix()) - clusterNumber := rand.Int() % len(clusters) + seed := rand.New(rand.NewSource(time.Now().Unix())) + clusterNumber := seed.Int() % len(clusters) return &v1alpha1.ApplicationDestination{ Namespace: opts.Namespace, Name: clusters[clusterNumber].Name, 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/gen-resources/generators/project_generator.go b/hack/gen-resources/generators/project_generator.go index 9f07cea1de9a1..7eee295af7f07 100644 --- a/hack/gen-resources/generators/project_generator.go +++ b/hack/gen-resources/generators/project_generator.go @@ -2,9 +2,9 @@ package generator import ( "context" - "log" "fmt" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "log" "github.com/argoproj/argo-cd/v2/hack/gen-resources/util" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" diff --git a/hack/gen-resources/generators/repo_generator.go b/hack/gen-resources/generators/repo_generator.go index 390dd27052069..11cc47f023d1a 100644 --- a/hack/gen-resources/generators/repo_generator.go +++ b/hack/gen-resources/generators/repo_generator.go @@ -33,7 +33,7 @@ func NewRepoGenerator(clientSet *kubernetes.Clientset) Generator { func fetchRepos(token string, page int) ([]Repo, error) { client := &http.Client{} - req, _ := http.NewRequest("GET", fmt.Sprintf("https://api.github.com/repos/argoproj/argocd-example-apps/forks?per_page=100&page=%v", page), nil) + req, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("https://api.github.com/repos/argoproj/argocd-example-apps/forks?per_page=100&page=%v", page), nil) req.Header.Set("Authorization", token) resp, err := client.Do(req) if err != nil { diff --git a/hack/gen-resources/util/gen_options_parser.go b/hack/gen-resources/util/gen_options_parser.go index b352305f55437..08fb37ab9b653 100644 --- a/hack/gen-resources/util/gen_options_parser.go +++ b/hack/gen-resources/util/gen_options_parser.go @@ -1,8 +1,8 @@ package util import ( - "os" "gopkg.in/yaml.v2" + "os" ) type SourceOpts struct { @@ -33,7 +33,7 @@ type ClusterOpts struct { ValuesFilePath string `yaml:"valuesFilePath"` DestinationNamespace string `yaml:"destinationNamespace"` ClusterNamePrefix string `yaml:"clusterNamePrefix"` - Concurrency int `yaml:"parallel"` + Concurrency int `yaml:"parallel"` } type GenerateOpts struct { diff --git a/hack/gen-resources/util/sizedwaitgroup.go b/hack/gen-resources/util/sizedwaitgroup.go index b43011ff802c9..6c6d4fb1c5fff 100644 --- a/hack/gen-resources/util/sizedwaitgroup.go +++ b/hack/gen-resources/util/sizedwaitgroup.go @@ -24,7 +24,7 @@ // Based upon sync.WaitGroup, SizedWaitGroup allows to start multiple // routines and to wait for their end using the simple API. -// SizedWaitGroup adds the feature of limiting the maximum number of +// Package util SizedWaitGroup adds the feature of limiting the maximum number of // concurrently started routines. It could for example be used to start // multiples routines querying a database but without sending too much // queries in order to not overload the given database. diff --git a/hack/generate-proto.sh b/hack/generate-proto.sh index d544bd045904f..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,19 +98,20 @@ 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() { SWAGGER_ROOT="$1" - EXPECTED_COLLISIONS="$2" SWAGGER_OUT="${PROJECT_ROOT}/assets/swagger.json" PRIMARY_SWAGGER=$(mktemp) COMBINED_SWAGGER=$(mktemp) - cat < "${PRIMARY_SWAGGER}" + cat <"${PRIMARY_SWAGGER}" { "swagger": "2.0", "info": { @@ -112,8 +125,19 @@ EOF rm -f "${SWAGGER_OUT}" - find "${SWAGGER_ROOT}" -name '*.swagger.json' -exec swagger mixin -c "${EXPECTED_COLLISIONS}" "${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)' "${COMBINED_SWAGGER}" > "${SWAGGER_OUT}" + 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"}} | + del(.definitions.v1alpha1OptionalArray) | + .definitions.v1alpha1ApplicationSourcePluginParameter.properties.map = {"description":"Map is the value of a map type parameter.","type":"object","additionalProperties":{"type":"string"}} | + 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}" /bin/rm "${PRIMARY_SWAGGER}" "${COMBINED_SWAGGER}" } @@ -124,9 +148,7 @@ clean_swagger() { find "${SWAGGER_ROOT}" -name '*.swagger.json' -delete } -echo "If additional types are added, the number of expected collisions may need to be increased" -EXPECTED_COLLISION_COUNT=95 -collect_swagger server ${EXPECTED_COLLISION_COUNT} +collect_swagger server clean_swagger server clean_swagger reposerver clean_swagger controller diff --git a/hack/installers/checksums/add-helm-checksums.sh b/hack/installers/checksums/add-helm-checksums.sh index 47292390d8789..95bf2b2566b69 100755 --- a/hack/installers/checksums/add-helm-checksums.sh +++ b/hack/installers/checksums/add-helm-checksums.sh @@ -3,7 +3,10 @@ # Usage: ./add-helm-checksums.sh 3.9.4 # use the desired version set -e - for arch in amd64 arm64 ppc64le s390x; do wget "https://get.helm.sh/helm-v$1-linux-$arch.tar.gz.sha256sum" -O "helm-v$1-linux-$arch.tar.gz.sha256" done + +for arch in amd64 arm64; do + wget "https://get.helm.sh/helm-v$1-darwin-$arch.tar.gz.sha256sum" -O "helm-v$1-darwin-$arch.tar.gz.sha256" +done \ No newline at end of file diff --git a/hack/installers/checksums/helm-v3.11.1-linux-amd64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.11.1-linux-amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..f1b701654f838 --- /dev/null +++ b/hack/installers/checksums/helm-v3.11.1-linux-amd64.tar.gz.sha256 @@ -0,0 +1 @@ +0b1be96b66fab4770526f136f5f1a385a47c41923d33aab0dcb500e0f6c1bf7c helm-v3.11.1-linux-amd64.tar.gz diff --git a/hack/installers/checksums/helm-v3.11.1-linux-arm64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.11.1-linux-arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..ea0e0cc0b50ca --- /dev/null +++ b/hack/installers/checksums/helm-v3.11.1-linux-arm64.tar.gz.sha256 @@ -0,0 +1 @@ +919173e8fb7a3b54d76af9feb92e49e86d5a80c5185020bae8c393fa0f0de1e8 helm-v3.11.1-linux-arm64.tar.gz diff --git a/hack/installers/checksums/helm-v3.11.1-linux-ppc64le.tar.gz.sha256 b/hack/installers/checksums/helm-v3.11.1-linux-ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..bc06e69aac086 --- /dev/null +++ b/hack/installers/checksums/helm-v3.11.1-linux-ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +6ab8f2e253c115b17eda1e10e96d1637047efd315e9807bcb1d0d0bcad278ab7 helm-v3.11.1-linux-ppc64le.tar.gz diff --git a/hack/installers/checksums/helm-v3.11.1-linux-s390x.tar.gz.sha256 b/hack/installers/checksums/helm-v3.11.1-linux-s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..b0403aa122856 --- /dev/null +++ b/hack/installers/checksums/helm-v3.11.1-linux-s390x.tar.gz.sha256 @@ -0,0 +1 @@ +ab133e6b709c8107dc4f8f62838947350adb8e23d76b8c2c592ff4c09bc956ef helm-v3.11.1-linux-s390x.tar.gz diff --git a/hack/installers/checksums/helm-v3.11.2-linux-amd64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.11.2-linux-amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..56e53bec70d0e --- /dev/null +++ b/hack/installers/checksums/helm-v3.11.2-linux-amd64.tar.gz.sha256 @@ -0,0 +1 @@ +781d826daec584f9d50a01f0f7dadfd25a3312217a14aa2fbb85107b014ac8ca helm-v3.11.2-linux-amd64.tar.gz diff --git a/hack/installers/checksums/helm-v3.11.2-linux-arm64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.11.2-linux-arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..c88970e874f59 --- /dev/null +++ b/hack/installers/checksums/helm-v3.11.2-linux-arm64.tar.gz.sha256 @@ -0,0 +1 @@ +0a60baac83c3106017666864e664f52a4e16fbd578ac009f9a85456a9241c5db helm-v3.11.2-linux-arm64.tar.gz diff --git a/hack/installers/checksums/helm-v3.11.2-linux-ppc64le.tar.gz.sha256 b/hack/installers/checksums/helm-v3.11.2-linux-ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..ddcdbc4de06dd --- /dev/null +++ b/hack/installers/checksums/helm-v3.11.2-linux-ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +04cbb8d053f2d8023e5cc6b771e9fa384fdd341eb7193a0fb592b7e2a036bf3d helm-v3.11.2-linux-ppc64le.tar.gz diff --git a/hack/installers/checksums/helm-v3.11.2-linux-s390x.tar.gz.sha256 b/hack/installers/checksums/helm-v3.11.2-linux-s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..b888b1a2166c9 --- /dev/null +++ b/hack/installers/checksums/helm-v3.11.2-linux-s390x.tar.gz.sha256 @@ -0,0 +1 @@ +9793b80711c2fd82dec6f9742415fffb762d41ca20033d4413364d372517f958 helm-v3.11.2-linux-s390x.tar.gz diff --git a/hack/installers/checksums/helm-v3.12.0-linux-amd64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.12.0-linux-amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..7462379983ea9 --- /dev/null +++ b/hack/installers/checksums/helm-v3.12.0-linux-amd64.tar.gz.sha256 @@ -0,0 +1 @@ +da36e117d6dbc57c8ec5bab2283222fbd108db86c83389eebe045ad1ef3e2c3b helm-v3.12.0-linux-amd64.tar.gz diff --git a/hack/installers/checksums/helm-v3.12.0-linux-arm64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.12.0-linux-arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..3c6199cc3751f --- /dev/null +++ b/hack/installers/checksums/helm-v3.12.0-linux-arm64.tar.gz.sha256 @@ -0,0 +1 @@ +658839fed8f9be2169f5df68e55cb2f0aa731a50df454caf183186766800bbd0 helm-v3.12.0-linux-arm64.tar.gz diff --git a/hack/installers/checksums/helm-v3.12.0-linux-ppc64le.tar.gz.sha256 b/hack/installers/checksums/helm-v3.12.0-linux-ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..cae34431dba6d --- /dev/null +++ b/hack/installers/checksums/helm-v3.12.0-linux-ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +252d952b0e1b4ed2013710ddedf687ed5545d9f95a4fd72de0ff9617ff69155c helm-v3.12.0-linux-ppc64le.tar.gz diff --git a/hack/installers/checksums/helm-v3.12.0-linux-s390x.tar.gz.sha256 b/hack/installers/checksums/helm-v3.12.0-linux-s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..3dd96d5670d5d --- /dev/null +++ b/hack/installers/checksums/helm-v3.12.0-linux-s390x.tar.gz.sha256 @@ -0,0 +1 @@ +727474fb1684aa2349a77c54340c11ff09b19862d972c2403185fb163fec13ae helm-v3.12.0-linux-s390x.tar.gz diff --git a/hack/installers/checksums/helm-v3.12.1-linux-amd64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.12.1-linux-amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..9a9fdc145bb6a --- /dev/null +++ b/hack/installers/checksums/helm-v3.12.1-linux-amd64.tar.gz.sha256 @@ -0,0 +1 @@ +1a7074f58ef7190f74ce6db5db0b70e355a655e2013c4d5db2317e63fa9e3dea helm-v3.12.1-linux-amd64.tar.gz diff --git a/hack/installers/checksums/helm-v3.12.1-linux-arm64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.12.1-linux-arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..a0c153758e688 --- /dev/null +++ b/hack/installers/checksums/helm-v3.12.1-linux-arm64.tar.gz.sha256 @@ -0,0 +1 @@ +50548d4fedef9d8d01d1ed5a2dd5c849271d1017127417dc4c7ef6777ae68f7e helm-v3.12.1-linux-arm64.tar.gz diff --git a/hack/installers/checksums/helm-v3.12.1-linux-ppc64le.tar.gz.sha256 b/hack/installers/checksums/helm-v3.12.1-linux-ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..2d51832d19aff --- /dev/null +++ b/hack/installers/checksums/helm-v3.12.1-linux-ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +32b25dba14549a4097bf3dd62221cf6df06279ded391f7479144e3a215982aaf helm-v3.12.1-linux-ppc64le.tar.gz diff --git a/hack/installers/checksums/helm-v3.12.1-linux-s390x.tar.gz.sha256 b/hack/installers/checksums/helm-v3.12.1-linux-s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..053b446be9913 --- /dev/null +++ b/hack/installers/checksums/helm-v3.12.1-linux-s390x.tar.gz.sha256 @@ -0,0 +1 @@ +f243b564cf7e4081fffdfe5a39487f6442fc439586a1f50cc59dd801c3e636a5 helm-v3.12.1-linux-s390x.tar.gz 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/helm-v3.14.1-linux-amd64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.1-linux-amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..cc06e12986311 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.1-linux-amd64.tar.gz.sha256 @@ -0,0 +1 @@ +75496ea824f92305ff7d28af37f4af57536bf5138399c824dff997b9d239dd42 helm-v3.14.1-linux-amd64.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.1-linux-arm64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.1-linux-arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..63f791b234ec4 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.1-linux-arm64.tar.gz.sha256 @@ -0,0 +1 @@ +f865b8ad4228fd0990bbc5b50615eb6cb9eb31c9a9ca7238401ed897bbbe9033 helm-v3.14.1-linux-arm64.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.1-linux-ppc64le.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.1-linux-ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..17b9b1e625fac --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.1-linux-ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +4d853ab8fe3462287c7272fbadd5f73531ecdd6fa0db37d31630e41ae1ae21de helm-v3.14.1-linux-ppc64le.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.1-linux-s390x.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.1-linux-s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..232ec10e03fc6 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.1-linux-s390x.tar.gz.sha256 @@ -0,0 +1 @@ +19bf07999c7244bfeb0fd27152919b9faa1148cf43910edbb98efa9150058a98 helm-v3.14.1-linux-s390x.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.2-darwin-amd64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.2-darwin-amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..8c2cdef022af2 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.2-darwin-amd64.tar.gz.sha256 @@ -0,0 +1 @@ +64c633ae194bde77b7e7b7936a2814a7417817dc8b7bb7d270bd24a7a17b8d12 helm-v3.14.2-darwin-amd64.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.2-darwin-arm64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.2-darwin-arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..a81e6ce01561f --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.2-darwin-arm64.tar.gz.sha256 @@ -0,0 +1 @@ +ff502fd39b06497fa3d5a51ec2ced02b9fcfdb0e9a948d315fb1b2f13ddc39fb helm-v3.14.2-darwin-arm64.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.2-linux-amd64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.2-linux-amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..22049267fd24e --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.2-linux-amd64.tar.gz.sha256 @@ -0,0 +1 @@ +0885a501d586c1e949e9b113bf3fb3290b0bbf74db9444a1d8c2723a143006a5 helm-v3.14.2-linux-amd64.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.2-linux-arm64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.2-linux-arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..17320419ee7e6 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.2-linux-arm64.tar.gz.sha256 @@ -0,0 +1 @@ +c65d6a9557bb359abc2c0d26670de850b52327dc3976ad6f9e14c298ea3e1b61 helm-v3.14.2-linux-arm64.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.2-linux-ppc64le.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.2-linux-ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..8ffe4ebe40e62 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.2-linux-ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +f3bc8582ff151e619cd285d9cdf9fef1c5733ee5522d8bed2ef680ef07f87223 helm-v3.14.2-linux-ppc64le.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.2-linux-s390x.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.2-linux-s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..d14a74799e6a2 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.2-linux-s390x.tar.gz.sha256 @@ -0,0 +1 @@ +7bda34aa26638e5116b31385f3b781172572175bf4c1ae00c87d8b154458ed94 helm-v3.14.2-linux-s390x.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.3-darwin-amd64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.3-darwin-amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..5e2a74f27b822 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.3-darwin-amd64.tar.gz.sha256 @@ -0,0 +1 @@ +4d5d01a94c7d6b07e71690dc1988bf3229680284c87f4242d28c6f1cc99653be helm-v3.14.3-darwin-amd64.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.3-darwin-arm64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.3-darwin-arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..bcd34d12bb3ac --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.3-darwin-arm64.tar.gz.sha256 @@ -0,0 +1 @@ +dff794152b62b7c1a9ff615d510f8657bcd7a3727c668e0d9d4955f70d5f7573 helm-v3.14.3-darwin-arm64.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.3-linux-amd64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.3-linux-amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..03d2c21b76f0d --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.3-linux-amd64.tar.gz.sha256 @@ -0,0 +1 @@ +3c90f24e180f8c207b8a18e5ec82cb0fa49858a7a0a86e4ed52a98398681e00b helm-v3.14.3-linux-amd64.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.3-linux-arm64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.3-linux-arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..fd99cd4e7e2d7 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.3-linux-arm64.tar.gz.sha256 @@ -0,0 +1 @@ +85e1573e76fa60af14ba7e9ec75db2129b6884203be866893fa0b3f7e41ccd5e helm-v3.14.3-linux-arm64.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.3-linux-ppc64le.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.3-linux-ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..1b6a9770e6310 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.3-linux-ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +aab121ca470e2a502cda849a9b3e92eeb9a32e213b0f0a79a95a04e375d26ce7 helm-v3.14.3-linux-ppc64le.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.3-linux-s390x.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.3-linux-s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..4ec7daaa0cd19 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.3-linux-s390x.tar.gz.sha256 @@ -0,0 +1 @@ +d64fa8aced3244b549377741dc4e2db8109e5270c0723c11b547a9da5f99ad43 helm-v3.14.3-linux-s390x.tar.gz diff --git a/hack/installers/checksums/kustomize_5.0.1_darwin_amd64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.0.1_darwin_amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..ea459765dff6b --- /dev/null +++ b/hack/installers/checksums/kustomize_5.0.1_darwin_amd64.tar.gz.sha256 @@ -0,0 +1 @@ +4a2b9f7fad0355c8bea08da6dd9c48e790df5f357983280998d80b8dc7ad3def kustomize_5.0.1_darwin_amd64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.0.1_darwin_arm64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.0.1_darwin_arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..170c7942be3d4 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.0.1_darwin_arm64.tar.gz.sha256 @@ -0,0 +1 @@ +b264fe931e85d8ca7c7ac47872695b1fa39fe2b73cfc0d58cbdca0bde69d0bc0 kustomize_5.0.1_darwin_arm64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.0.1_linux_amd64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.0.1_linux_amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..2af67b55d8ee4 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.0.1_linux_amd64.tar.gz.sha256 @@ -0,0 +1 @@ +dca623b36aef84fbdf28f79d02e9b3705ff641424ac1f872d5420dadb12fb78d kustomize_5.0.1_linux_amd64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.0.1_linux_arm64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.0.1_linux_arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..621146c893ea2 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.0.1_linux_arm64.tar.gz.sha256 @@ -0,0 +1 @@ +c6e036c5c7eee4c15f7544e441ced5cb6cf9eba24a011c25008df5617cd2fb85 kustomize_5.0.1_linux_arm64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.0.1_linux_ppc64le.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.0.1_linux_ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..27cd2529d5228 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.0.1_linux_ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +75df309f1efa92c57ccd15603be4fb6806e5b62f3e882d892ad34a4ee3c293f4 kustomize_5.0.1_linux_ppc64le.tar.gz diff --git a/hack/installers/checksums/kustomize_5.0.1_linux_s390x.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.0.1_linux_s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..2ef2cab8bdd37 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.0.1_linux_s390x.tar.gz.sha256 @@ -0,0 +1 @@ +1c67b27bf72a1c5615bd901b1971a88d920da8255038f13af7bb61695b08fda5 kustomize_5.0.1_linux_s390x.tar.gz diff --git a/hack/installers/checksums/kustomize_5.1.0_darwin_amd64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.1.0_darwin_amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..946ee03acae12 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.1.0_darwin_amd64.tar.gz.sha256 @@ -0,0 +1 @@ +08664a17820138a68b7cbe302b1b63f4ec19c6e0838385f789ee0470f026ba25 kustomize_5.1.0_darwin_amd64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.1.0_linux_amd64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.1.0_linux_amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..2eb13d31cfd88 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.1.0_linux_amd64.tar.gz.sha256 @@ -0,0 +1 @@ +52f4cf1ba34d38fd55a9bef819e329c9a4561f5f57f8f539346038ab5026dda8 kustomize_5.1.0_linux_amd64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.1.0_linux_arm64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.1.0_linux_arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..a5040fa6fd9a1 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.1.0_linux_arm64.tar.gz.sha256 @@ -0,0 +1 @@ +4e333ccf092bb72ef5d6bfd3e1f8abb161b5540ce47a53474d70c58eeb99f0a9 kustomize_5.1.0_linux_arm64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.1.0_linux_ppc64le.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.1.0_linux_ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..3f7eda534c9c9 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.1.0_linux_ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +83abeb44857db6a06f9dd35c5c40282b3b9ae4ca73e6306c52be604668964f0e kustomize_5.1.0_linux_ppc64le.tar.gz diff --git a/hack/installers/checksums/kustomize_5.1.0_linux_s390x.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.1.0_linux_s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..ded7a81927051 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.1.0_linux_s390x.tar.gz.sha256 @@ -0,0 +1 @@ +acff69cfb8e11b7df73c71610379ad76c003d638294f9bc98ceb0b68655e953e kustomize_5.1.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/installers/install-codegen-go-tools.sh b/hack/installers/install-codegen-go-tools.sh index c6ebfc8902cee..6c9775ff46274 100755 --- a/hack/installers/install-codegen-go-tools.sh +++ b/hack/installers/install-codegen-go-tools.sh @@ -26,7 +26,7 @@ mkdir -p $GOBIN #go_mod_install github.com/gogo/protobuf/protoc-gen-gogo go_mod_install github.com/gogo/protobuf/protoc-gen-gogofast -# protoc-gen-grpc-gateway is used to build .pb.gw.go files from from .proto files +# protoc-gen-grpc-gateway is used to build .pb.gw.go files from .proto files go_mod_install github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway # # protoc-gen-swagger is used to build swagger.json diff --git a/hack/installers/install-gotestsum.sh b/hack/installers/install-gotestsum.sh new file mode 100755 index 0000000000000..27b497696ccdc --- /dev/null +++ b/hack/installers/install-gotestsum.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -eux -o pipefail + +# Code from: https://github.com/argoproj/argo-rollouts/blob/f650a1fd0ba7beb2125e1598410515edd572776f/hack/installers/install-dev-tools.sh + +PROJECT_ROOT=$(cd $(dirname ${BASH_SOURCE})/../..; pwd) +DIST_PATH="${PROJECT_ROOT}/dist" +PATH="${DIST_PATH}:${PATH}" + +mkdir -p ${DIST_PATH} + +gotestsum_version=1.11.0 + +OS=$(go env GOOS) +ARCH=$(go env GOARCH) + +export TARGET_FILE=gotestsum_${gotestsum_version}_${OS}_${ARCH}.tar.gz +temp_path="/tmp/${TARGET_FILE}" +url=https://github.com/gotestyourself/gotestsum/releases/download/v${gotestsum_version}/gotestsum_${gotestsum_version}_${OS}_${ARCH}.tar.gz +[ -e ${temp_path} ] || curl -sLf --retry 3 -o ${temp_path} ${url} + +mkdir -p /tmp/gotestsum-${gotestsum_version} +tar -xvzf ${temp_path} -C /tmp/gotestsum-${gotestsum_version} +cp /tmp/gotestsum-${gotestsum_version}/gotestsum ${DIST_PATH}/gotestsum +chmod +x ${DIST_PATH}/gotestsum +gotestsum --version diff --git a/hack/installers/install-helm-linux.sh b/hack/installers/install-helm.sh similarity index 63% rename from hack/installers/install-helm-linux.sh rename to hack/installers/install-helm.sh index 6371fd452c204..ef3882fdaf688 100755 --- a/hack/installers/install-helm-linux.sh +++ b/hack/installers/install-helm.sh @@ -3,10 +3,10 @@ set -eux -o pipefail . $(dirname $0)/../tool-versions.sh -export TARGET_FILE=helm-v${helm3_version}-linux-${ARCHITECTURE}.tar.gz +export TARGET_FILE=helm-v${helm3_version}-${INSTALL_OS}-${ARCHITECTURE}.tar.gz -[ -e $DOWNLOADS/${TARGET_FILE} ] || curl -sLf --retry 3 -o $DOWNLOADS/${TARGET_FILE} https://get.helm.sh/helm-v${helm3_version}-linux-$ARCHITECTURE.tar.gz +[ -e $DOWNLOADS/${TARGET_FILE} ] || curl -sLf --retry 3 -o $DOWNLOADS/${TARGET_FILE} https://get.helm.sh/helm-v${helm3_version}-$INSTALL_OS-$ARCHITECTURE.tar.gz $(dirname $0)/compare-chksum.sh mkdir -p /tmp/helm && tar -C /tmp/helm -xf $DOWNLOADS/${TARGET_FILE} -sudo install -m 0755 /tmp/helm/linux-$ARCHITECTURE/helm $BIN/helm +sudo install -m 0755 /tmp/helm/$INSTALL_OS-$ARCHITECTURE/helm $BIN/helm helm version --client diff --git a/hack/installers/install-kustomize.sh b/hack/installers/install-kustomize.sh index 7a8f2ed3e0efc..3457d1613243f 100755 --- a/hack/installers/install-kustomize.sh +++ b/hack/installers/install-kustomize.sh @@ -8,7 +8,7 @@ INSTALL_PATH="${INSTALL_PATH:-$PROJECT_ROOT/dist}" PATH="${INSTALL_PATH}:${PATH}" [ -d $INSTALL_PATH ] || mkdir -p $INSTALL_PATH -KUSTOMIZE_VERSION=${KUSTOMIZE_VERSION:-$kustomize4_version} +KUSTOMIZE_VERSION=${KUSTOMIZE_VERSION:-$kustomize5_version} if [ -z $INSTALL_OS ]; then echo "install kustomize error: unsupported operating system" diff --git a/hack/installers/install-lint-tools.sh b/hack/installers/install-lint-tools.sh index a77e67c6fb0cc..b4f68e464b15b 100755 --- a/hack/installers/install-lint-tools.sh +++ b/hack/installers/install-lint-tools.sh @@ -1,4 +1,4 @@ #!/bin/bash set -eux -o pipefail -GO111MODULE=on go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.2 +GO111MODULE=on go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.54.0 diff --git a/hack/known_types/main.go b/hack/known_types/main.go index a2e4665a0eb1a..be8bcfdc7b50c 100644 --- a/hack/known_types/main.go +++ b/hack/known_types/main.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "go/importer" + "go/token" "go/types" "os" "strings" @@ -36,15 +37,16 @@ func newCommand() *cobra.Command { packagePath := args[1] outputPath := args[2] - // nolint:staticcheck - imprt := importer.For("source", nil) + if !strings.HasPrefix(packagePath, packagePrefix) { + return fmt.Errorf("package must be under %s", packagePrefix) + } + + imprt := importer.ForCompiler(token.NewFileSet(), "source", nil) pkg, err := imprt.Import(packagePath) if err != nil { return err } - if !strings.HasPrefix(packagePath, packagePrefix) { - return fmt.Errorf("package must be under %s", packagePrefix) - } + shortPackagePath := strings.TrimPrefix(packagePath, packagePrefix) var mapItems []string @@ -82,7 +84,7 @@ func init() {%s } } - return os.WriteFile(outputPath, []byte(res), 0644) + return os.WriteFile(outputPath, []byte(res+"\n"), 0644) }, } command.Flags().StringVar(&docsOutputPath, "docs", "", "Docs output file path") diff --git a/hack/ssh_known_hosts b/hack/ssh_known_hosts index 31a7bae3fce5d..39d09f58685c2 100644 --- a/hack/ssh_known_hosts +++ b/hack/ssh_known_hosts @@ -1,6 +1,13 @@ -# This file was automatically generated. DO NOT EDIT -bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== -github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== +# This file was automatically generated by hack/update-ssh-known-hosts.sh. DO NOT EDIT +[ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +[ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +[ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= +bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= +bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO +bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M= +github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 diff --git a/hack/test.sh b/hack/test.sh index 1ca29343be2b2..454a58d749291 100755 --- a/hack/test.sh +++ b/hack/test.sh @@ -15,12 +15,4 @@ fi mkdir -p $TEST_RESULTS -report() { - set -eux -o pipefail - - go-junit-report < $TEST_RESULTS/test.out > $TEST_RESULTS/junit.xml -} - -trap 'report' EXIT - -go test $TEST_FLAGS -failfast $* 2>&1 | tee $TEST_RESULTS/test.out +GODEBUG="tarinsecurepath=0,zipinsecurepath=0" ${DIST_DIR}/gotestsum --rerun-fails-report=rerunreport.txt --junitfile=$TEST_RESULTS/junit.xml --format=testname --rerun-fails="$RERUN_FAILS" --packages="$PACKAGES" -- $TEST_FLAGS $* diff --git a/hack/tool-versions.sh b/hack/tool-versions.sh index dd342c1e2af6c..e87dc54590afd 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.10.3 +helm3_version=3.14.3 kubectl_version=1.17.8 kubectx_version=0.6.3 -kustomize4_version=4.5.7 +kustomize5_version=5.2.1 protoc_version=3.17.3 diff --git a/hack/trigger-release.sh b/hack/trigger-release.sh index 508ecfa0c141f..b7f843fad7fd6 100755 --- a/hack/trigger-release.sh +++ b/hack/trigger-release.sh @@ -4,33 +4,11 @@ NEW_TAG="${1}" GIT_REMOTE="${2}" -COMMIT_MSG="${3}" -origToken="" set -ue -restoreToken() { - if test "$origToken" != ""; then - echo ">> Restoring original Git comment char" - git config core.commentChar "$origToken" - fi -} - -cleanLocalTriggerTag() { - if test "$TRIGGER_TAG" != ""; then - echo ">> Remove trigger tag '${TRIGGER_TAG}' from local repository." - git tag -d $TRIGGER_TAG - fi -} - -cleanup() { - restoreToken - cleanLocalTriggerTag -} - if test "${NEW_TAG}" = "" -o "${GIT_REMOTE}" = ""; then - echo "!! Usage: $0 [path to release notes file]" >&2 - echo "You can use generate-release-notes.sh to generate the release notes file." >&2 + echo "!! Usage: $0 " >&2 exit 1 fi @@ -41,8 +19,6 @@ if ! echo "${NEW_TAG}" | egrep -q '^v[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)*$'; then exit 1 fi -TRIGGER_TAG="release-${NEW_TAG}" - # Check whether we are in correct branch of local repository RELEASE_BRANCH="${NEW_TAG%\.[0-9]*}" RELEASE_BRANCH="release-${RELEASE_BRANCH#*v}" @@ -55,18 +31,9 @@ fi echo ">> Working in release branch '${RELEASE_BRANCH}'" -# Check for trigger tag existing in local repo -if git tag -l | grep -q -E "^${TRIGGER_TAG}$"; then - echo "!! Release tag '${TRIGGER_TAG}' already exists in local repository" >&2 - exit 1 -fi - -# Check for trigger tag existing in remote repo -if git ls-remote ${GIT_REMOTE} refs/tags/${TRIGGER_TAG} | grep -q -E "^${NEW_TAG}$"; then - echo "!! Target trigger tag '${TRIGGER_TAG}' already exists in remote '${GIT_REMOTE}'" >&2 - echo "!! Another operation currently in progress?" >&2 - exit 1 -fi +echo ">> Ensuring release branch is up to date." +# make sure release branch is up to date +git pull ${GIT_REMOTE} ${RELEASE_BRANCH} # Check for target (version) tag in local repo if git tag -l | grep -q -E "^${NEW_TAG}$"; then @@ -75,35 +42,15 @@ if git tag -l | grep -q -E "^${NEW_TAG}$"; then fi # Check for target (version) tag in remote repo -if git ls-remote ${GIT_REMOTE} refs/tags/${NEW_TAG} | grep -q -E "^${NEW_TAG}$"; then +if git ls-remote ${GIT_REMOTE} refs/tags/${NEW_TAG} | grep -q -E "${NEW_TAG}$"; then echo "!! Target version tag '${NEW_TAG}' already exists in remote '${GIT_REMOTE}'" >&2 exit 1 fi -echo ">> Creating new release '${NEW_TAG}' by pushing '${TRIGGER_TAG}' to '${GIT_REMOTE}'" - -GIT_ARGS="" -if test "${COMMIT_MSG}" != ""; then - if ! test -f "${COMMIT_MSG}"; then - echo "!! Release notes at '${COMMIT_MSG}' do not exist or are not readable." >&2 - exit 1 - fi - GIT_ARGS="-F ${COMMIT_MSG}" -fi - -# We need different git comment char than '#', because markdown makes extensive -# use of '#' - we chose ';' for our operation. -origToken=$(git config core.commentChar || echo '#') -echo ">> Saving original Git comment char '${origToken}' and setting it to ';' for this run" -if ! git config core.commentChar ';'; then - echo "!! Could not set git config commentChar ';'" >&2 - exit 1 -fi - -trap cleanup SIGINT EXIT +echo ">> Creating new release '${NEW_TAG}' by pushing '${NEW_TAG}' to '${GIT_REMOTE}'" -# Create trigger tag in local repository -git tag -a ${GIT_ARGS} ${TRIGGER_TAG} +# Create new tag in local repository +git tag ${NEW_TAG} -# Push the trigger tag to remote repository -git push ${GIT_REMOTE} ${TRIGGER_TAG} +# Push the new tag to remote repository +git push ${GIT_REMOTE} ${NEW_TAG} 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/hack/update-ssh-known-hosts.sh b/hack/update-ssh-known-hosts.sh index aa74c6489addd..5f2bedeb5b8ff 100755 --- a/hack/update-ssh-known-hosts.sh +++ b/hack/update-ssh-known-hosts.sh @@ -3,22 +3,33 @@ set -e KNOWN_HOSTS_FILE=$(dirname "$0")/ssh_known_hosts -HEADER="# This file was automatically generated. DO NOT EDIT" +HEADER="# This file was automatically generated by hack/update-ssh-known-hosts.sh. DO NOT EDIT" echo "$HEADER" > $KNOWN_HOSTS_FILE -ssh-keyscan github.com gitlab.com bitbucket.org ssh.dev.azure.com vs-ssh.visualstudio.com | sort -u >> $KNOWN_HOSTS_FILE +{ \ + ssh-keyscan github.com gitlab.com bitbucket.org ssh.dev.azure.com vs-ssh.visualstudio.com && \ + ssh-keyscan -p 443 ssh.github.com ; \ +} | sort -u >> $KNOWN_HOSTS_FILE chmod 0644 $KNOWN_HOSTS_FILE # Public SSH keys can be verified at the following URLs: # - github.com: https://help.github.com/articles/github-s-ssh-key-fingerprints/ +# - ssh.github.com: https://docs.github.com/en/authentication/troubleshooting-ssh/using-ssh-over-the-https-port#updating-known-hosts # - gitlab.com: https://docs.gitlab.com/ee/user/gitlab_com/#ssh-host-keys-fingerprints # - bitbucket.org: https://confluence.atlassian.com/bitbucket/ssh-keys-935365775.html # - ssh.dev.azure.com, vs-ssh.visualstudio.com: https://docs.microsoft.com/en-us/azure/devops/repos/git/use-ssh-keys-to-authenticate?view=azure-devops diff - <(ssh-keygen -l -f $KNOWN_HOSTS_FILE | sort -k 3) < /dev/null || exit 1 + line=$(yq '.jobs["test-e2e"].strategy.matrix["k3s-version"][]' .github/workflows/ci-build.yaml | \ + jq --arg minor_version "$minor_version" --raw-input --slurp --raw-output \ + 'split("\n")[:-1] | map(sub("\\.[0-9]+$"; "")) | join(", ") | "| \($minor_version) | \(.) |"') + out+="$line\n" +done + +git checkout "release-$argocd_minor_version" + + +printf "$out" > docs/operator-manual/tested-kubernetes-versions.md diff --git a/manifests/base/application-controller-deployment/argocd-application-controller-deployment.yaml b/manifests/base/application-controller-deployment/argocd-application-controller-deployment.yaml new file mode 100644 index 0000000000000..68dd75de2f47f --- /dev/null +++ b/manifests/base/application-controller-deployment/argocd-application-controller-deployment.yaml @@ -0,0 +1,252 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: argocd-application-controller + app.kubernetes.io/part-of: argocd + app.kubernetes.io/component: application-controller + name: argocd-application-controller +spec: + selector: + matchLabels: + app.kubernetes.io/name: argocd-application-controller + replicas: 1 + template: + metadata: + labels: + app.kubernetes.io/name: argocd-application-controller + spec: + containers: + - args: + - /usr/local/bin/argocd-application-controller + env: + - name: ARGOCD_RECONCILIATION_TIMEOUT + valueFrom: + configMapKeyRef: + name: argocd-cm + key: timeout.reconciliation + optional: true + - name: ARGOCD_HARD_RECONCILIATION_TIMEOUT + valueFrom: + configMapKeyRef: + 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 + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS + valueFrom: + 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 + - name: ARGOCD_APPLICATION_CONTROLLER_OPERATION_PROCESSORS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.operation.processors + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_LOGFORMAT + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.log.format + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_LOGLEVEL + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.log.level + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_METRICS_CACHE_EXPIRATION + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.metrics.cache.expiration + 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 + - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + 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 + - name: ARGOCD_APPLICATION_CONTROLLER_PERSIST_RESOURCE_HEALTH + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.resource.health.persist + optional: true + - name: ARGOCD_APP_STATE_CACHE_EXPIRATION + valueFrom: + 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 + - name: REDIS_COMPRESSION + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: redis.compression + optional: true + - name: REDISDB + valueFrom: + 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 + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_ADDRESS + valueFrom: + 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 + - name: ARGOCD_CONTROLLER_SHARDING_ALGORITHM + valueFrom: + 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_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 + ports: + - containerPort: 8082 + readinessProbe: + httpGet: + path: /healthz + port: 8082 + initialDelaySeconds: 5 + periodSeconds: 10 + securityContext: + runAsNonRoot: true + readOnlyRootFilesystem: true + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + workingDir: /home/argocd + volumeMounts: + - name: argocd-repo-server-tls + mountPath: /app/config/controller/tls + - name: argocd-home + mountPath: /home/argocd + serviceAccountName: argocd-application-controller + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/name: argocd-application-controller + topologyKey: kubernetes.io/hostname + - weight: 5 + podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/part-of: argocd + topologyKey: kubernetes.io/hostname + volumes: + - emptyDir: {} + name: argocd-home + - name: argocd-repo-server-tls + secret: + secretName: argocd-repo-server-tls + optional: true + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt diff --git a/manifests/base/application-controller-deployment/argocd-application-controller-service.yaml b/manifests/base/application-controller-deployment/argocd-application-controller-service.yaml new file mode 100644 index 0000000000000..a769e75468483 --- /dev/null +++ b/manifests/base/application-controller-deployment/argocd-application-controller-service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: argocd-application-controller + app.kubernetes.io/name: argocd-application-controller + app.kubernetes.io/part-of: argocd + name: argocd-application-controller +spec: + ports: + - name: application-controller + protocol: TCP + port: 8082 + targetPort: 8082 + - name: metrics + protocol: TCP + port: 8084 + targetPort: 8084 + selector: + app.kubernetes.io/name: argocd-application-controller \ No newline at end of file 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 new file mode 100644 index 0000000000000..733a378e013e0 --- /dev/null +++ b/manifests/base/application-controller-deployment/kustomization.yaml @@ -0,0 +1,9 @@ +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 d0c9ed68d7f1a..d974edffdd618 100644 --- a/manifests/base/application-controller/argocd-application-controller-statefulset.yaml +++ b/manifests/base/application-controller/argocd-application-controller-statefulset.yaml @@ -18,8 +18,8 @@ spec: app.kubernetes.io/name: argocd-application-controller spec: containers: - - command: - - argocd-application-controller + - args: + - /usr/local/bin/argocd-application-controller env: - name: ARGOCD_CONTROLLER_REPLICAS value: "1" @@ -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,28 +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 + - name: ARGOCD_APPLICATION_CONTROLLER_KUBECTL_PARALLELISM_LIMIT + valueFrom: + 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 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/applicationset-controller/argocd-applicationset-controller-deployment.yaml b/manifests/base/applicationset-controller/argocd-applicationset-controller-deployment.yaml index da67ac8433e84..b24124ccb833f 100644 --- a/manifests/base/applicationset-controller/argocd-applicationset-controller-deployment.yaml +++ b/manifests/base/applicationset-controller/argocd-applicationset-controller-deployment.yaml @@ -3,8 +3,8 @@ kind: Deployment metadata: labels: app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset - app.kubernetes.io/component: controller + app.kubernetes.io/part-of: argocd + app.kubernetes.io/component: applicationset-controller name: argocd-applicationset-controller spec: selector: @@ -16,114 +16,192 @@ spec: app.kubernetes.io/name: argocd-applicationset-controller spec: containers: - - command: - - entrypoint.sh - - argocd-applicationset-controller + - args: + - /usr/local/bin/argocd-applicationset-controller image: quay.io/argoproj/argocd:latest imagePullPolicy: Always name: argocd-applicationset-controller ports: - - containerPort: 7000 - name: webhook - - containerPort: 8080 - name: metrics + - containerPort: 7000 + name: webhook + - containerPort: 8080 + name: metrics env: - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_LEADER_ELECTION - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.enable.leader.election - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACE - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.namespace - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER - valueFrom: - configMapKeyRef: - key: repo.server - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_POLICY - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.policy - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.debug - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_LOGFORMAT - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.log.format - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_LOGLEVEL - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.log.level - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_DRY_RUN - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.dryrun - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_GIT_MODULES_ENABLED - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.enable.git.submodule - name: argocd-cmd-params-cm - optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.enable.progressive.rollouts - name: argocd-cmd-params-cm - optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_ANNOTATIONS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.global.preserved.annotations + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_LABELS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.global.preserved.labels + name: argocd-cmd-params-cm + optional: true + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_LEADER_ELECTION + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.leader.election + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER + valueFrom: + configMapKeyRef: + key: repo.server + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_POLICY + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.policy + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.policy.override + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.debug + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_LOGFORMAT + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.log.format + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_LOGLEVEL + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.log.level + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_DRY_RUN + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.dryrun + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_GIT_MODULES_ENABLED + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.git.submodule + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.progressive.syncs + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.new.git.file.globbing + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: applicationsetcontroller.repo.server.plaintext + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: applicationsetcontroller.repo.server.strict.tls + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: applicationsetcontroller.repo.server.timeout.seconds + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_CONCURRENT_RECONCILIATIONS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: applicationsetcontroller.concurrent.reconciliations.max + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.namespaces + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.scm.root.ca.path + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: applicationsetcontroller.allowed.scm.providers + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: applicationsetcontroller.enable.scm.providers + optional: true volumeMounts: - - mountPath: /app/config/ssh - name: ssh-known-hosts - - mountPath: /app/config/tls - name: tls-certs - - mountPath: /app/config/gpg/source - name: gpg-keys - - mountPath: /app/config/gpg/keys - name: gpg-keyring - - mountPath: /tmp - name: tmp + - mountPath: /app/config/ssh + name: ssh-known-hosts + - mountPath: /app/config/tls + name: tls-certs + - mountPath: /app/config/gpg/source + name: gpg-keys + - mountPath: /app/config/gpg/keys + name: gpg-keyring + - mountPath: /tmp + name: tmp + - name: argocd-repo-server-tls + mountPath: /app/config/reposerver/tls securityContext: capabilities: drop: - - ALL + - ALL allowPrivilegeEscalation: false - readOnlyRootFilesystem: true + readOnlyRootFilesystem: true runAsNonRoot: true seccompProfile: type: RuntimeDefault serviceAccountName: argocd-applicationset-controller volumes: - - configMap: - name: argocd-ssh-known-hosts-cm - name: ssh-known-hosts - - configMap: - name: argocd-tls-certs-cm - name: tls-certs - - configMap: - name: argocd-gpg-keys-cm - name: gpg-keys - - emptyDir: {} - name: gpg-keyring - - emptyDir: {} - name: tmp + - configMap: + name: argocd-ssh-known-hosts-cm + name: ssh-known-hosts + - configMap: + name: argocd-tls-certs-cm + name: tls-certs + - configMap: + name: argocd-gpg-keys-cm + name: gpg-keys + - emptyDir: { } + name: gpg-keyring + - emptyDir: { } + name: tmp + - name: argocd-repo-server-tls + secret: + secretName: argocd-repo-server-tls + optional: true + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt diff --git a/manifests/base/applicationset-controller/argocd-applicationset-controller-role.yaml b/manifests/base/applicationset-controller/argocd-applicationset-controller-role.yaml index 0e729346ada5e..47c7ac9805a50 100644 --- a/manifests/base/applicationset-controller/argocd-applicationset-controller-role.yaml +++ b/manifests/base/applicationset-controller/argocd-applicationset-controller-role.yaml @@ -3,8 +3,8 @@ kind: Role metadata: labels: app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset - app.kubernetes.io/component: controller + app.kubernetes.io/part-of: argocd + app.kubernetes.io/component: applicationset-controller name: argocd-applicationset-controller rules: - apiGroups: diff --git a/manifests/base/applicationset-controller/argocd-applicationset-controller-rolebinding.yaml b/manifests/base/applicationset-controller/argocd-applicationset-controller-rolebinding.yaml index 4d647ee29246c..90bc99bbbaa8a 100644 --- a/manifests/base/applicationset-controller/argocd-applicationset-controller-rolebinding.yaml +++ b/manifests/base/applicationset-controller/argocd-applicationset-controller-rolebinding.yaml @@ -3,8 +3,8 @@ kind: RoleBinding metadata: labels: app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset - app.kubernetes.io/component: controller + app.kubernetes.io/part-of: argocd + app.kubernetes.io/component: applicationset-controller name: argocd-applicationset-controller roleRef: apiGroup: rbac.authorization.k8s.io diff --git a/manifests/base/applicationset-controller/argocd-applicationset-controller-sa.yaml b/manifests/base/applicationset-controller/argocd-applicationset-controller-sa.yaml index 0366d09ce05b2..89c6a85fc7c7b 100644 --- a/manifests/base/applicationset-controller/argocd-applicationset-controller-sa.yaml +++ b/manifests/base/applicationset-controller/argocd-applicationset-controller-sa.yaml @@ -4,6 +4,6 @@ kind: ServiceAccount metadata: labels: app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset - app.kubernetes.io/component: controller + app.kubernetes.io/part-of: argocd + app.kubernetes.io/component: applicationset-controller name: argocd-applicationset-controller \ No newline at end of file diff --git a/manifests/base/applicationset-controller/argocd-applicationset-controller-service.yaml b/manifests/base/applicationset-controller/argocd-applicationset-controller-service.yaml index 6ce17e46e1c9b..48a5fcd040f1e 100644 --- a/manifests/base/applicationset-controller/argocd-applicationset-controller-service.yaml +++ b/manifests/base/applicationset-controller/argocd-applicationset-controller-service.yaml @@ -2,9 +2,9 @@ apiVersion: v1 kind: Service metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller spec: ports: diff --git a/manifests/base/config/argocd-ssh-known-hosts-cm.yaml b/manifests/base/config/argocd-ssh-known-hosts-cm.yaml index 9c810567b2654..0f30fa5671662 100644 --- a/manifests/base/config/argocd-ssh-known-hosts-cm.yaml +++ b/manifests/base/config/argocd-ssh-known-hosts-cm.yaml @@ -7,12 +7,18 @@ metadata: name: argocd-ssh-known-hosts-cm data: ssh_known_hosts: | - bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== - github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== + # This file was automatically generated by hack/update-ssh-known-hosts.sh. DO NOT EDIT + [ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + [ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + [ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= + bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= + bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO + bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M= + github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H - github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= - github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl \ 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 dd2d37fea62e8..7ff5985f44a90 100644 --- a/manifests/base/dex/argocd-dex-server-deployment.yaml +++ b/manifests/base/dex/argocd-dex-server-deployment.yaml @@ -20,7 +20,7 @@ spec: - name: copyutil image: quay.io/argoproj/argocd:latest imagePullPolicy: Always - command: [cp, -n, /usr/local/bin/argocd, /shared/argocd-dex] + command: [/bin/cp, -n, /usr/local/bin/argocd, /shared/argocd-dex] volumeMounts: - mountPath: /shared name: static-files @@ -37,7 +37,7 @@ spec: type: RuntimeDefault containers: - name: dex - image: ghcr.io/dexidp/dex:v2.35.3 + image: ghcr.io/dexidp/dex:v2.38.0 imagePullPolicy: Always command: [/shared/argocd-dex, rundex] env: diff --git a/manifests/base/dex/argocd-dex-server-service.yaml b/manifests/base/dex/argocd-dex-server-service.yaml index 7aeabca1e674e..cffbf006ae624 100644 --- a/manifests/base/dex/argocd-dex-server-service.yaml +++ b/manifests/base/dex/argocd-dex-server-service.yaml @@ -9,6 +9,7 @@ metadata: spec: ports: - name: http + appProtocol: TCP protocol: TCP port: 5556 targetPort: 5556 diff --git a/manifests/base/notification/argocd-notifications-cm.yaml b/manifests/base/notification/argocd-notifications-cm.yaml index 8139efd7e701a..c022fa50ded35 100644 --- a/manifests/base/notification/argocd-notifications-cm.yaml +++ b/manifests/base/notification/argocd-notifications-cm.yaml @@ -1,4 +1,8 @@ apiVersion: v1 kind: ConfigMap metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-cm diff --git a/manifests/base/notification/argocd-notifications-controller-deployment.yaml b/manifests/base/notification/argocd-notifications-controller-deployment.yaml index 94d01e7343f8a..876a207c16e42 100644 --- a/manifests/base/notification/argocd-notifications-controller-deployment.yaml +++ b/manifests/base/notification/argocd-notifications-controller-deployment.yaml @@ -1,6 +1,10 @@ apiVersion: apps/v1 kind: Deployment metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller spec: strategy: @@ -29,8 +33,33 @@ spec: - key: ca.crt path: ca.crt containers: - - command: - - argocd-notifications + - args: + - /usr/local/bin/argocd-notifications + env: + - name: ARGOCD_NOTIFICATIONS_CONTROLLER_LOGFORMAT + valueFrom: + configMapKeyRef: + key: notificationscontroller.log.format + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_NOTIFICATIONS_CONTROLLER_LOGLEVEL + valueFrom: + configMapKeyRef: + key: notificationscontroller.log.level + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_NAMESPACES + valueFrom: + configMapKeyRef: + 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/notification/argocd-notifications-controller-metrics-service.yaml b/manifests/base/notification/argocd-notifications-controller-metrics-service.yaml index c5ec6160cb310..2126735c7d274 100644 --- a/manifests/base/notification/argocd-notifications-controller-metrics-service.yaml +++ b/manifests/base/notification/argocd-notifications-controller-metrics-service.yaml @@ -2,7 +2,9 @@ apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: notifications-controller app.kubernetes.io/name: argocd-notifications-controller-metrics + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller-metrics spec: ports: diff --git a/manifests/base/notification/argocd-notifications-controller-network-policy.yaml b/manifests/base/notification/argocd-notifications-controller-network-policy.yaml index d7bb5d0679c2a..54a820c8b3243 100644 --- a/manifests/base/notification/argocd-notifications-controller-network-policy.yaml +++ b/manifests/base/notification/argocd-notifications-controller-network-policy.yaml @@ -1,6 +1,10 @@ apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller-network-policy spec: podSelector: diff --git a/manifests/base/notification/argocd-notifications-controller-role.yaml b/manifests/base/notification/argocd-notifications-controller-role.yaml index 9d0ff3b78ac74..11d561f4292ee 100644 --- a/manifests/base/notification/argocd-notifications-controller-role.yaml +++ b/manifests/base/notification/argocd-notifications-controller-role.yaml @@ -1,6 +1,10 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller rules: - apiGroups: diff --git a/manifests/base/notification/argocd-notifications-controller-rolebinding.yaml b/manifests/base/notification/argocd-notifications-controller-rolebinding.yaml index 0cacec4fd2820..d10904b3daa75 100644 --- a/manifests/base/notification/argocd-notifications-controller-rolebinding.yaml +++ b/manifests/base/notification/argocd-notifications-controller-rolebinding.yaml @@ -1,6 +1,10 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller roleRef: apiGroup: rbac.authorization.k8s.io diff --git a/manifests/base/notification/argocd-notifications-secret.yaml b/manifests/base/notification/argocd-notifications-secret.yaml index a58f865becffa..fc54cfc18adfa 100644 --- a/manifests/base/notification/argocd-notifications-secret.yaml +++ b/manifests/base/notification/argocd-notifications-secret.yaml @@ -1,5 +1,9 @@ apiVersion: v1 kind: Secret metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-secret type: Opaque diff --git a/manifests/base/redis/argocd-redis-deployment.yaml b/manifests/base/redis/argocd-redis-deployment.yaml index 02c18192a76ed..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.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: Always args: - "--save" @@ -33,6 +33,7 @@ spec: ports: - containerPort: 6379 securityContext: + readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: diff --git a/manifests/base/redis/argocd-redis-rolebinding.yaml b/manifests/base/redis/argocd-redis-rolebinding.yaml deleted file mode 100644 index 87caaa2cd6f57..0000000000000 --- a/manifests/base/redis/argocd-redis-rolebinding.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - labels: - app.kubernetes.io/component: redis - app.kubernetes.io/name: argocd-redis - app.kubernetes.io/part-of: argocd - name: argocd-redis -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: argocd-redis -subjects: -- kind: ServiceAccount - name: argocd-redis diff --git a/manifests/base/redis/kustomization.yaml b/manifests/base/redis/kustomization.yaml index 71a6ec42240db..4a0b64c4da6a8 100644 --- a/manifests/base/redis/kustomization.yaml +++ b/manifests/base/redis/kustomization.yaml @@ -3,16 +3,6 @@ kind: Kustomization resources: - argocd-redis-deployment.yaml -- argocd-redis-rolebinding.yaml - argocd-redis-sa.yaml - argocd-redis-service.yaml - argocd-redis-network-policy.yaml - -vars: -- name: ARGOCD_REDIS_SERVICE - objref: - kind: Service - name: argocd-redis - apiVersion: v1 - fieldref: - fieldpath: metadata.name \ No newline at end of file diff --git a/manifests/base/repo-server/argocd-repo-server-deployment.yaml b/manifests/base/repo-server/argocd-repo-server-deployment.yaml index 4966ff9e65ae8..2c30c8ad1d71b 100644 --- a/manifests/base/repo-server/argocd-repo-server-deployment.yaml +++ b/manifests/base/repo-server/argocd-repo-server-deployment.yaml @@ -21,7 +21,8 @@ spec: - name: argocd-repo-server image: quay.io/argoproj/argocd:latest imagePullPolicy: Always - command: [ "sh", "-c", "entrypoint.sh argocd-repo-server --redis $(ARGOCD_REDIS_SERVICE):6379"] + args: + - /usr/local/bin/argocd-repo-server env: - name: ARGOCD_RECONCILIATION_TIMEOUT valueFrom: @@ -47,6 +48,18 @@ spec: name: argocd-cmd-params-cm key: reposerver.parallelism.limit optional: true + - name: ARGOCD_REPO_SERVER_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: reposerver.listen.address + optional: true + - name: ARGOCD_REPO_SERVER_LISTEN_METRICS_ADDRESS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: reposerver.metrics.listen.address + optional: true - name: ARGOCD_REPO_SERVER_DISABLE_TLS valueFrom: configMapKeyRef: @@ -107,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: @@ -137,12 +162,42 @@ spec: key: reposerver.streamed.manifest.max.extracted.size name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE + valueFrom: + configMapKeyRef: + key: reposerver.helm.manifest.max.extracted.size + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: reposerver.disable.helm.manifest.max.extracted.size + optional: true + - name: ARGOCD_REVISION_CACHE_LOCK_TIMEOUT + valueFrom: + configMapKeyRef: + key: reposerver.revision.cache.lock.timeout + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_GIT_MODULES_ENABLED valueFrom: configMapKeyRef: 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 @@ -194,7 +249,7 @@ spec: name: plugins initContainers: - command: - - cp + - /bin/cp - -n - /usr/local/bin/argocd - /var/run/argocd/argocd-cmp-server diff --git a/manifests/base/repo-server/argocd-repo-server-network-policy.yaml b/manifests/base/repo-server/argocd-repo-server-network-policy.yaml index 2b3fb72b557b5..267dfa81adc49 100644 --- a/manifests/base/repo-server/argocd-repo-server-network-policy.yaml +++ b/manifests/base/repo-server/argocd-repo-server-network-policy.yaml @@ -7,18 +7,21 @@ spec: matchLabels: app.kubernetes.io/name: argocd-repo-server policyTypes: - - Ingress + - Ingress ingress: - from: - - podSelector: - matchLabels: - app.kubernetes.io/name: argocd-server - - podSelector: - matchLabels: - app.kubernetes.io/name: argocd-application-controller - - podSelector: - matchLabels: - app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-server + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-application-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-applicationset-controller ports: - protocol: TCP port: 8081 diff --git a/manifests/base/server/argocd-server-deployment.yaml b/manifests/base/server/argocd-server-deployment.yaml index b5a9e405bd4d0..0ebeb70e08531 100644 --- a/manifests/base/server/argocd-server-deployment.yaml +++ b/manifests/base/server/argocd-server-deployment.yaml @@ -20,140 +20,141 @@ spec: - name: argocd-server image: quay.io/argoproj/argocd:latest imagePullPolicy: Always - command: [argocd-server] + args: + - /usr/local/bin/argocd-server 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: @@ -162,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: @@ -180,40 +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 + - name: ARGOCD_SERVER_METRICS_LISTEN_ADDRESS + valueFrom: + 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 779e674a608c9..b33820950fcb6 100644 --- a/manifests/cluster-rbac/server/argocd-server-clusterrole.yaml +++ b/manifests/cluster-rbac/server/argocd-server-clusterrole.yaml @@ -32,7 +32,20 @@ rules: - "argoproj.io" resources: - "applications" + - "applicationsets" verbs: - get - list - watch +- apiGroups: + - batch + resources: + - jobs + verbs: + - create # supports triggering jobs from UI +- apiGroups: + - argoproj.io + resources: + - workflows + verbs: + - create # supports triggering workflows from UI diff --git a/manifests/core-install.yaml b/manifests/core-install.yaml index 304e5b2a0f06e..05f1deaad58fe 100644 --- a/manifests/core-install.yaml +++ b/manifests/core-install.yaml @@ -287,8 +287,15 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be + passed to helm template, defined as a map. This takes + precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -303,12 +310,22 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -326,6 +343,10 @@ spec: definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether to + apply common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -334,6 +355,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -549,8 +624,15 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be + passed to helm template, defined as a map. This takes + precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -565,12 +647,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -589,6 +682,10 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -597,6 +694,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -718,7 +869,8 @@ spec: properties: name: description: Name is an alternate way of specifying the target - cluster by its symbolic name + cluster by its symbolic name. This must be set if Server is + not set. type: string namespace: description: Namespace specifies the target namespace for the @@ -726,8 +878,9 @@ spec: namespace-scoped resources that have not set a value for .metadata.namespace type: string server: - description: Server specifies the URL of the target cluster and - must be set to the Kubernetes control plane API + description: Server specifies the URL of the target cluster's + Kubernetes control plane API. This must be set if Name is not + set. type: string type: object ignoreDifferences: @@ -927,8 +1080,15 @@ spec: type: array values: description: Values specifies Helm values to be passed to - helm template, typically defined as a block + helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be passed + to helm template, defined as a map. This takes precedence + over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -943,12 +1103,22 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether to + apply env variables substitution for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -965,6 +1135,10 @@ spec: definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether to apply + common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -973,6 +1147,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize adds + to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas override + specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -1180,8 +1408,15 @@ spec: type: array values: description: Values specifies Helm values to be passed to - helm template, typically defined as a block + helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be passed + to helm template, defined as a map. This takes precedence + over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -1196,12 +1431,22 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -1219,6 +1464,10 @@ spec: definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether to apply + common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -1227,6 +1476,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas override + specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -1319,7 +1622,7 @@ spec: as part of automated sync (default: false)' type: boolean selfHeal: - description: 'SelfHeal specifes whether to revert resources + description: 'SelfHeal specifies whether to revert resources back to their desired state upon modification in the cluster (default: false)' type: boolean @@ -1383,7 +1686,7 @@ spec: conditions items: description: ApplicationCondition contains details about an application - condition, which is usally an error or warning + condition, which is usually an error or warning properties: lastTransitionTime: description: LastTransitionTime is the time the condition was @@ -1402,6 +1705,10 @@ spec: - type type: object type: array + controllerNamespace: + description: ControllerNamespace indicates the namespace in which + the application controller is located + type: string health: description: Health contains information about the application's current health status @@ -1435,6 +1742,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 @@ -1581,8 +1901,15 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be + passed to helm template, defined as a map. This takes + precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -1597,12 +1924,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -1621,6 +1959,10 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -1629,6 +1971,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -1846,8 +2242,16 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. + ValuesObject takes precedence over Values, so use + one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to + be passed to helm template, defined as a map. This + takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -1862,12 +2266,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -1886,6 +2301,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -1894,6 +2314,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -2256,8 +2730,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined as - a block + a block. ValuesObject takes precedence over + Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as a + map. This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -2272,12 +2753,24 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution + for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -2296,6 +2789,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors + or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -2304,14 +2802,68 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string - version: - description: Version controls which version of - Kustomize to use for rendering manifests + namespace: + description: Namespace sets the namespace that + Kustomize adds to all resources type: string - type: object - path: - description: Path is a directory path within the Git - repository, and is only valid for applications sourced + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array + version: + description: Version controls which version of + Kustomize to use for rendering manifests + type: string + type: object + path: + description: Path is a directory path within the Git + repository, and is only valid for applications sourced from Git. type: string plugin: @@ -2537,8 +3089,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined - as a block + as a block. ValuesObject takes precedence + over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as + a map. This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -2555,12 +3114,24 @@ spec: additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution + for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -2579,6 +3150,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies + whether to apply common labels to resource + selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -2587,6 +3163,61 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that + Kustomize adds to all resources + type: string + patches: + description: Patches is a list of Kustomize + patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize + Replicas override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -2720,6 +3351,19 @@ spec: syncResult: description: SyncResult is the result of a Sync operation properties: + managedNamespaceMetadata: + description: ManagedNamespaceMetadata contains the current + sync state of managed namespace metadata + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object resources: description: Resources contains a list of sync result items for each individual resource in a sync operation @@ -2922,8 +3566,16 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. + ValuesObject takes precedence over Values, so use + one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to + be passed to helm template, defined as a map. This + takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -2938,12 +3590,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -2962,6 +3625,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -2970,6 +3638,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -3198,8 +3920,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined as - a block + a block. ValuesObject takes precedence over Values, + so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as a map. + This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -3214,12 +3943,24 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution for + annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -3238,6 +3979,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -3246,6 +3992,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -3428,7 +4228,8 @@ spec: properties: name: description: Name is an alternate way of specifying the - target cluster by its symbolic name + target cluster by its symbolic name. This must be set + if Server is not set. type: string namespace: description: Namespace specifies the target namespace @@ -3437,10 +4238,47 @@ spec: not set a value for .metadata.namespace type: string server: - description: Server specifies the URL of the target cluster - and must be set to the Kubernetes control plane API + description: Server specifies the URL of the target cluster's + Kubernetes control plane API. This must be set if Name + is not set. type: string type: object + ignoreDifferences: + description: IgnoreDifferences is a reference to the application's + ignored differences used for comparison + items: + description: ResourceIgnoreDifferences contains resource + filter and list of json paths which should be ignored + during comparison with live state. + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + description: ManagedFieldsManagers is a list of trusted + managers. Fields mutated by those managers will take + precedence over the desired state defined in the SCM + and won't be displayed in diffs + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array source: description: Source is a reference to the application's source used for comparison @@ -3579,8 +4417,16 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. + ValuesObject takes precedence over Values, so use + one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to + be passed to helm template, defined as a map. This + takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -3595,12 +4441,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -3619,6 +4476,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -3627,6 +4489,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -3855,8 +4771,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined as - a block + a block. ValuesObject takes precedence over Values, + so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as a map. + This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -3871,12 +4794,24 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution for + annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -3895,6 +4830,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -3903,33 +4843,87 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string - version: - description: Version controls which version of Kustomize - to use for rendering manifests + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources type: string - type: object - path: - description: Path is a directory path within the Git - repository, and is only valid for applications sourced - from Git. - type: string - plugin: - description: Plugin holds config management plugin specific - options - properties: - env: - description: Env is a list of environment variable - entries + patches: + description: Patches is a list of Kustomize patches items: - description: EnvEntry represents an entry in the - application's environment properties: - name: - description: Name is the name of the variable, - usually expressed in uppercase + options: + additionalProperties: + type: boolean + type: object + patch: type: string - value: - description: Value is the value of the variable + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array + version: + description: Version controls which version of Kustomize + to use for rendering manifests + type: string + type: object + path: + description: Path is a directory path within the Git + repository, and is only valid for applications sourced + from Git. + type: string + plugin: + description: Plugin holds config management plugin specific + options + properties: + env: + description: Env is a list of environment variable + entries + items: + description: EnvEntry represents an entry in the + application's environment + properties: + name: + description: Name is the name of the variable, + usually expressed in uppercase + type: string + value: + description: Value is the value of the variable type: string required: - name @@ -4043,6 +5037,8 @@ spec: type: object spec: properties: + applyNestedSelectors: + type: boolean generators: items: properties: @@ -4238,6 +5234,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4247,10 +5246,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4259,10 +5264,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4396,6 +5450,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4405,10 +5462,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4417,10 +5480,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4713,6 +5825,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4722,10 +5837,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4734,10 +5855,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4871,6 +6041,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4880,10 +6053,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4892,10 +6071,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5192,6 +6420,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5201,10 +6432,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5213,10 +6450,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5350,6 +6636,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5359,10 +6648,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5371,25 +6666,74 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string - version: + namespace: type: string - type: object - path: - type: string - plugin: - properties: - env: + patches: items: properties: - name: + options: + additionalProperties: + type: boolean + type: object + patch: type: string - value: + path: type: string - required: + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: - name - value type: object @@ -5475,6 +6819,10 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object required: - repoURL - revision @@ -5485,6 +6833,8 @@ spec: items: x-kubernetes-preserve-unknown-fields: true type: array + elementsYaml: + type: string template: properties: metadata: @@ -5645,6 +6995,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5654,10 +7007,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5666,10 +7025,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5803,6 +7211,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5812,10 +7223,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5824,10 +7241,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5928,8 +7394,6 @@ spec: - metadata - spec type: object - required: - - elements type: object matrix: properties: @@ -6128,6 +7592,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6137,10 +7604,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6149,10 +7622,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -6286,6 +7808,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6295,10 +7820,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6307,10 +7838,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -6603,6 +8183,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6612,10 +8195,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6624,10 +8213,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -6761,6 +8399,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6770,10 +8411,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6782,10 +8429,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7082,6 +8778,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7091,10 +8790,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7103,10 +8808,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7240,6 +8994,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7249,10 +9006,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7261,10 +9024,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7365,6 +9177,10 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object required: - repoURL - revision @@ -7375,6 +9191,8 @@ spec: items: x-kubernetes-preserve-unknown-fields: true type: array + elementsYaml: + type: string template: properties: metadata: @@ -7535,6 +9353,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7544,10 +9365,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7556,10 +9383,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7693,6 +9569,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7702,10 +9581,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7714,10 +9599,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7818,153 +9752,49 @@ spec: - metadata - spec type: object - required: - - elements type: object matrix: x-kubernetes-preserve-unknown-fields: true merge: x-kubernetes-preserve-unknown-fields: true - pullRequest: + plugin: properties: - bitbucketServer: + configMapRef: properties: - api: - type: string - basicAuth: - properties: - passwordRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - username: - type: string - required: - - passwordRef - - username - type: object - project: - type: string - repo: + name: type: string required: - - api - - project - - repo + - name type: object - filters: - items: - properties: - branchMatch: - type: string - type: object - type: array - gitea: + input: properties: - api: - type: string - insecure: - type: boolean - owner: - type: string - repo: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName + parameters: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true type: object - required: - - api - - owner - - repo type: object - github: + requeueAfterSeconds: + format: int64 + type: integer + template: properties: - api: - type: string - appSecretName: - type: string - labels: - items: - type: string - type: array - owner: - type: string - repo: - type: string - tokenRef: + metadata: properties: - key: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - owner - - repo - type: object - gitlab: - properties: - api: - type: string - labels: - items: - type: string - type: array - project: - type: string - pullRequestState: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - project - type: object - requeueAfterSeconds: - format: int64 - type: integer - template: - properties: - metadata: - properties: - annotations: - additionalProperties: - type: string - type: object - finalizers: - items: - type: string - type: array - labels: - additionalProperties: - type: string - type: object - name: - type: string - namespace: + namespace: type: string type: object spec: @@ -8106,6 +9936,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8115,10 +9948,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8127,10 +9966,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -8264,6 +10152,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8273,10 +10164,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8285,10 +10182,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -8389,12 +10335,30 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object + required: + - configMapRef type: object - scmProvider: + pullRequest: properties: - azureDevOps: + azuredevops: properties: - accessTokenRef: + api: + type: string + labels: + items: + type: string + type: array + organization: + type: string + project: + type: string + repo: + type: string + tokenRef: properties: key: type: string @@ -8404,46 +10368,58 @@ spec: - key - secretName type: object - allBranches: - type: boolean - api: - type: string - organization: - type: string - teamProject: - type: string required: - - accessTokenRef - organization - - teamProject + - project + - repo type: object bitbucket: properties: - allBranches: - type: boolean - appPasswordRef: + api: + type: string + basicAuth: properties: - key: - type: string - secretName: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: type: string required: - - key - - secretName + - passwordRef + - username + type: object + bearerToken: + properties: + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - tokenRef type: object owner: type: string - user: + repo: type: string required: - - appPasswordRef - owner - - user + - repo type: object bitbucketServer: properties: - allBranches: - type: boolean api: type: string basicAuth: @@ -8466,41 +10442,32 @@ spec: type: object project: type: string + repo: + type: string required: - api - project + - repo type: object - cloneProtocol: - type: string filters: items: properties: branchMatch: type: string - labelMatch: - type: string - pathsDoNotExist: - items: - type: string - type: array - pathsExist: - items: - type: string - type: array - repositoryMatch: + targetBranchMatch: type: string type: object type: array gitea: properties: - allBranches: - type: boolean api: type: string insecure: type: boolean owner: type: string + repo: + type: string tokenRef: properties: key: @@ -8514,16 +10481,21 @@ spec: required: - api - owner + - repo type: object github: properties: - allBranches: - type: boolean api: type: string appSecretName: type: string - organization: + labels: + items: + type: string + type: array + owner: + type: string + repo: type: string tokenRef: properties: @@ -8536,18 +10508,23 @@ spec: - secretName type: object required: - - organization + - owner + - repo type: object gitlab: properties: - allBranches: - type: boolean api: type: string - group: - type: string - includeSubgroups: + insecure: type: boolean + labels: + items: + type: string + type: array + project: + type: string + pullRequestState: + type: string tokenRef: properties: key: @@ -8559,7 +10536,7 @@ spec: - secretName type: object required: - - group + - project type: object requeueAfterSeconds: format: int64 @@ -8724,6 +10701,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8733,10 +10713,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8745,23 +10731,72 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string - version: + namespace: type: string - type: object - path: - type: string - plugin: - properties: - env: + patches: items: properties: - name: - type: string - value: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: type: string required: - name @@ -8882,6 +10917,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8891,10 +10929,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8903,10 +10947,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -9008,511 +11101,203 @@ spec: - spec type: object type: object - selector: + scmProvider: properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - type: string - values: - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - type: object - type: object - type: object - type: array - template: - properties: - metadata: - properties: - annotations: - additionalProperties: - type: string - type: object - finalizers: - items: - type: string - type: array - labels: - additionalProperties: - type: string - type: object - name: - type: string - namespace: - type: string - type: object - spec: - properties: - destination: - properties: - name: - type: string - namespace: - type: string - server: - type: string - type: object - ignoreDifferences: - items: + awsCodeCommit: properties: - group: + allBranches: + type: boolean + region: type: string - jqPathExpressions: - items: - type: string - type: array - jsonPointers: - items: - type: string - type: array - kind: + role: type: string - managedFieldsManagers: + tagFilters: items: - type: string + properties: + key: + type: string + value: + type: string + required: + - key + type: object type: array - name: + type: object + azureDevOps: + properties: + accessTokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + allBranches: + type: boolean + api: type: string - namespace: + organization: + type: string + teamProject: type: string required: - - kind + - accessTokenRef + - organization + - teamProject type: object - type: array - info: - items: + bitbucket: properties: - name: + allBranches: + type: boolean + appPasswordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + owner: type: string - value: + user: type: string required: - - name - - value + - appPasswordRef + - owner + - user type: object - type: array - project: - type: string - revisionHistoryLimit: - format: int64 - type: integer - source: - properties: - chart: - type: string - directory: + bitbucketServer: + properties: + allBranches: + type: boolean + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + project: + type: string + required: + - api + - project + type: object + cloneProtocol: + type: string + filters: + items: properties: - exclude: + branchMatch: type: string - include: + labelMatch: type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean - type: object - helm: - properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: - type: boolean - valueFiles: + pathsDoNotExist: items: type: string type: array - values: - type: string - version: - type: string - type: object - kustomize: - properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: - type: boolean - images: + pathsExist: items: type: string type: array - namePrefix: - type: string - nameSuffix: - type: string - version: - type: string - type: object - path: - type: string - plugin: - properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - name: + repositoryMatch: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array type: object - ref: - type: string - repoURL: - type: string - targetRevision: - type: string - required: - - repoURL - type: object - sources: - items: + type: array + gitea: properties: - chart: + allBranches: + type: boolean + api: type: string - directory: + insecure: + type: boolean + owner: + type: string + tokenRef: properties: - exclude: + key: type: string - include: + secretName: type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean + required: + - key + - secretName type: object - helm: + required: + - api + - owner + type: object + github: + properties: + allBranches: + type: boolean + api: + type: string + appSecretName: + type: string + organization: + type: string + tokenRef: properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: - type: boolean - valueFiles: - items: - type: string - type: array - values: + key: type: string - version: + secretName: type: string + required: + - key + - secretName type: object - kustomize: - properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: - type: boolean - images: - items: - type: string - type: array - namePrefix: - type: string - nameSuffix: - type: string - version: - type: string - type: object - path: + required: + - organization + type: object + gitlab: + properties: + allBranches: + type: boolean + api: type: string - plugin: + group: + type: string + includeSharedProjects: + type: boolean + includeSubgroups: + type: boolean + insecure: + type: boolean + tokenRef: properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - name: + key: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array + secretName: + type: string + required: + - key + - secretName type: object - ref: - type: string - repoURL: - type: string - targetRevision: + topic: type: string required: - - repoURL - type: object - type: array - syncPolicy: - properties: - automated: - properties: - allowEmpty: - type: boolean - prune: - type: boolean - selfHeal: - type: boolean - type: object - managedNamespaceMetadata: - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - retry: - properties: - backoff: - properties: - duration: - type: string - factor: - format: int64 - type: integer - maxDuration: - type: string - type: object - limit: - format: int64 - type: integer - type: object - syncOptions: - items: - type: string - type: array - type: object - required: - - destination - - project - type: object - required: - - metadata - - spec - type: object - required: - - generators - type: object - merge: - properties: - generators: - items: - properties: - clusterDecisionResource: - properties: - configMapRef: - type: string - labelSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - type: string - values: - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - type: object + - group type: object - name: - type: string requeueAfterSeconds: format: int64 type: integer @@ -9676,6 +11461,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -9685,10 +11473,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9697,10 +11491,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -9834,6 +11677,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -9843,10 +11689,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9855,10 +11707,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -9963,34 +11864,2392 @@ spec: additionalProperties: type: string type: object - required: - - configMapRef type: object - clusters: + selector: properties: - selector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - type: string - values: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + type: array + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: items: type: string type: array - required: - - key - - operator + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array type: object - type: array - matchLabels: - additionalProperties: + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + required: + - generators + type: object + merge: + properties: + generators: + items: + properties: + clusterDecisionResource: + properties: + configMapRef: + type: string + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + name: + type: string + requeueAfterSeconds: + format: int64 + type: integer + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + required: + - configMapRef + type: object + clusters: + properties: + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + type: object + git: + properties: + directories: + items: + properties: + exclude: + type: boolean + path: + type: string + required: + - path + type: object + type: array + files: + items: + properties: + path: + type: string + required: + - path + type: object + type: array + pathParamPrefix: + type: string + repoURL: + type: string + requeueAfterSeconds: + format: int64 + type: integer + revision: + type: string + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string type: object + required: + - repoURL + - revision + type: object + list: + properties: + elements: + items: + x-kubernetes-preserve-unknown-fields: true + type: array + elementsYaml: + type: string template: properties: metadata: @@ -10151,6 +14410,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10160,10 +14422,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10172,10 +14440,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10309,6 +14626,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10318,10 +14638,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10330,10 +14656,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10434,42 +14809,30 @@ spec: - metadata - spec type: object - values: - additionalProperties: - type: string - type: object type: object - git: + matrix: + x-kubernetes-preserve-unknown-fields: true + merge: + x-kubernetes-preserve-unknown-fields: true + plugin: properties: - directories: - items: - properties: - exclude: - type: boolean - path: - type: string - required: - - path - type: object - type: array - files: - items: - properties: - path: - type: string - required: - - path - type: object - type: array - pathParamPrefix: - type: string - repoURL: - type: string + configMapRef: + properties: + name: + type: string + required: + - name + type: object + input: + properties: + parameters: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object requeueAfterSeconds: format: int64 type: integer - revision: - type: string template: properties: metadata: @@ -10630,6 +14993,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10639,10 +15005,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10651,10 +15023,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10788,6 +15209,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10797,10 +15221,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10809,10 +15239,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10906,23 +15385,219 @@ spec: type: array type: object required: - - destination - - project + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + required: + - configMapRef + type: object + pullRequest: + properties: + azuredevops: + properties: + api: + type: string + labels: + items: + type: string + type: array + organization: + type: string + project: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - organization + - project + - repo + type: object + bitbucket: + properties: + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + bearerToken: + properties: + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - tokenRef + type: object + owner: + type: string + repo: + type: string + required: + - owner + - repo + type: object + bitbucketServer: + properties: + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + project: + type: string + repo: + type: string + required: + - api + - project + - repo + type: object + filters: + items: + properties: + branchMatch: + type: string + targetBranchMatch: + type: string + type: object + type: array + gitea: + properties: + api: + type: string + insecure: + type: boolean + owner: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName type: object required: - - metadata - - spec + - api + - owner + - repo type: object - required: - - repoURL - - revision - type: object - list: - properties: - elements: - items: - x-kubernetes-preserve-unknown-fields: true - type: array + github: + properties: + api: + type: string + appSecretName: + type: string + labels: + items: + type: string + type: array + owner: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - owner + - repo + type: object + gitlab: + properties: + api: + type: string + insecure: + type: boolean + labels: + items: + type: string + type: array + project: + type: string + pullRequestState: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - project + type: object + requeueAfterSeconds: + format: int64 + type: integer template: properties: metadata: @@ -11083,6 +15758,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -11092,10 +15770,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11104,10 +15788,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -11241,6 +15974,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -11250,10 +15986,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11262,10 +16004,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -11366,17 +16157,81 @@ spec: - metadata - spec type: object - required: - - elements type: object - matrix: - x-kubernetes-preserve-unknown-fields: true - merge: - x-kubernetes-preserve-unknown-fields: true - pullRequest: + scmProvider: properties: + awsCodeCommit: + properties: + allBranches: + type: boolean + region: + type: string + role: + type: string + tagFilters: + items: + properties: + key: + type: string + value: + type: string + required: + - key + type: object + type: array + type: object + azureDevOps: + properties: + accessTokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + allBranches: + type: boolean + api: + type: string + organization: + type: string + teamProject: + type: string + required: + - accessTokenRef + - organization + - teamProject + type: object + bitbucket: + properties: + allBranches: + type: boolean + appPasswordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + owner: + type: string + user: + type: string + required: + - appPasswordRef + - owner + - user + type: object bitbucketServer: properties: + allBranches: + type: boolean api: type: string basicAuth: @@ -11399,30 +16254,41 @@ spec: type: object project: type: string - repo: - type: string required: - api - project - - repo type: object + cloneProtocol: + type: string filters: items: properties: branchMatch: type: string + labelMatch: + type: string + pathsDoNotExist: + items: + type: string + type: array + pathsExist: + items: + type: string + type: array + repositoryMatch: + type: string type: object type: array gitea: properties: + allBranches: + type: boolean api: type: string insecure: type: boolean owner: type: string - repo: - type: string tokenRef: properties: key: @@ -11436,21 +16302,16 @@ spec: required: - api - owner - - repo type: object github: properties: + allBranches: + type: boolean api: type: string - appSecretName: - type: string - labels: - items: - type: string - type: array - owner: - type: string - repo: + appSecretName: + type: string + organization: type: string tokenRef: properties: @@ -11463,21 +16324,22 @@ spec: - secretName type: object required: - - owner - - repo + - organization type: object gitlab: properties: + allBranches: + type: boolean api: type: string - labels: - items: - type: string - type: array - project: - type: string - pullRequestState: + group: type: string + includeSharedProjects: + type: boolean + includeSubgroups: + type: boolean + insecure: + type: boolean tokenRef: properties: key: @@ -11488,8 +16350,10 @@ spec: - key - secretName type: object + topic: + type: string required: - - project + - group type: object requeueAfterSeconds: format: int64 @@ -11654,6 +16518,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -11663,10 +16530,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11675,10 +16548,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -11812,6 +16734,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -11821,10 +16746,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11833,10 +16764,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -11937,654 +16917,622 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object type: object - scmProvider: + selector: properties: - azureDevOps: - properties: - accessTokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - allBranches: - type: boolean - api: - type: string - organization: - type: string - teamProject: - type: string - required: - - accessTokenRef - - organization - - teamProject - type: object - bitbucket: - properties: - allBranches: - type: boolean - appPasswordRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - owner: - type: string - user: - type: string - required: - - appPasswordRef - - owner - - user - type: object - bitbucketServer: - properties: - allBranches: - type: boolean - api: - type: string - basicAuth: - properties: - passwordRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - username: - type: string - required: - - passwordRef - - username - type: object - project: - type: string - required: - - api - - project - type: object - cloneProtocol: - type: string - filters: + matchExpressions: items: properties: - branchMatch: + key: type: string - labelMatch: + operator: type: string - pathsDoNotExist: - items: - type: string - type: array - pathsExist: + values: items: type: string type: array - repositoryMatch: - type: string + required: + - key + - operator type: object type: array - gitea: - properties: - allBranches: - type: boolean - api: - type: string - insecure: - type: boolean - owner: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - api - - owner + matchLabels: + additionalProperties: + type: string type: object - github: + type: object + type: object + type: array + mergeKeys: + items: + type: string + type: array + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: properties: - allBranches: - type: boolean - api: + group: type: string - appSecretName: + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: type: string - organization: + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object required: - - organization + - kind type: object - gitlab: + type: array + info: + items: properties: - allBranches: - type: boolean - api: + name: type: string - group: + value: type: string - includeSubgroups: - type: boolean - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object required: - - group + - name + - value type: object - requeueAfterSeconds: - format: int64 - type: integer - template: - properties: - metadata: - properties: - annotations: - additionalProperties: - type: string - type: object - finalizers: - items: - type: string - type: array - labels: - additionalProperties: - type: string - type: object - name: - type: string - namespace: - type: string - type: object - spec: - properties: - destination: - properties: - name: - type: string - namespace: - type: string - server: - type: string - type: object - ignoreDifferences: - items: - properties: - group: - type: string - jqPathExpressions: - items: - type: string - type: array - jsonPointers: - items: - type: string - type: array - kind: - type: string - managedFieldsManagers: - items: - type: string - type: array - name: - type: string - namespace: - type: string - required: - - kind - type: object - type: array - info: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - project: - type: string - revisionHistoryLimit: - format: int64 - type: integer - source: - properties: - chart: - type: string - directory: - properties: - exclude: - type: string - include: - type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean - type: object - helm: + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: + code: type: boolean - valueFiles: - items: - type: string - type: array - values: + name: type: string - version: + value: type: string + required: + - name + - value type: object - kustomize: + type: array + libs: + items: + type: string + type: array + tlas: + items: properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: + code: type: boolean - images: - items: - type: string - type: array - namePrefix: - type: string - nameSuffix: + name: type: string - version: + value: type: string + required: + - name + - value type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string path: type: string - plugin: + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string name: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array + namespace: + type: string + version: + type: string type: object - ref: + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: type: string - repoURL: + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: type: string - targetRevision: + value: type: string required: - - repoURL + - name + - value type: object - sources: - items: - properties: - chart: + type: array + name: + type: string + parameters: + items: + properties: + array: + items: type: string - directory: - properties: - exclude: - type: string - include: - type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean - type: object - helm: + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: + code: type: boolean - valueFiles: - items: - type: string - type: array - values: + name: type: string - version: + value: type: string + required: + - name + - value type: object - kustomize: + type: array + libs: + items: + type: string + type: array + tlas: + items: properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: + code: type: boolean - images: - items: - type: string - type: array - namePrefix: - type: string - nameSuffix: + name: type: string - version: + value: type: string + required: + - name + - value type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string path: type: string - plugin: + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string name: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array + namespace: + type: string + version: + type: string type: object - ref: - type: string - repoURL: - type: string - targetRevision: + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: type: string required: - - repoURL + - count + - name type: object type: array - syncPolicy: - properties: - automated: - properties: - allowEmpty: - type: boolean - prune: - type: boolean - selfHeal: - type: boolean - type: object - managedNamespaceMetadata: - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - retry: - properties: - backoff: - properties: - duration: - type: string - factor: - format: int64 - type: integer - maxDuration: - type: string - type: object - limit: - format: int64 - type: integer - type: object - syncOptions: - items: + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: type: string - type: array - type: object - required: - - destination - - project + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string required: - - metadata - - spec + - repoURL type: object - type: object - selector: - properties: - matchExpressions: - items: + type: array + syncPolicy: + properties: + automated: properties: - key: - type: string - operator: - type: string - values: - items: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: type: string - type: array - required: - - key - - operator + type: object + labels: + additionalProperties: + type: string + type: object type: object - type: array - matchLabels: - additionalProperties: - type: string - type: object - type: object - type: object - type: array - mergeKeys: - items: - type: string - type: array + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + required: + - generators + - mergeKeys + type: object + plugin: + properties: + configMapRef: + properties: + name: + type: string + required: + - name + type: object + input: + properties: + parameters: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + requeueAfterSeconds: + format: int64 + type: integer template: properties: metadata: @@ -12745,6 +17693,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -12754,10 +17705,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12766,10 +17723,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -12903,6 +17909,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -12912,10 +17921,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12924,10 +17939,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -13021,19 +18085,96 @@ spec: type: array type: object required: - - destination - - project + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + required: + - configMapRef + type: object + pullRequest: + properties: + azuredevops: + properties: + api: + type: string + labels: + items: + type: string + type: array + organization: + type: string + project: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - organization + - project + - repo + type: object + bitbucket: + properties: + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + bearerToken: + properties: + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - tokenRef type: object + owner: + type: string + repo: + type: string required: - - metadata - - spec + - owner + - repo type: object - required: - - generators - - mergeKeys - type: object - pullRequest: - properties: bitbucketServer: properties: api: @@ -13070,6 +18211,8 @@ spec: properties: branchMatch: type: string + targetBranchMatch: + type: string type: object type: array gitea: @@ -13129,6 +18272,8 @@ spec: properties: api: type: string + insecure: + type: boolean labels: items: type: string @@ -13313,6 +18458,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -13322,10 +18470,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13334,10 +18488,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -13471,6 +18674,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -13480,10 +18686,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13492,10 +18704,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -13599,6 +18860,26 @@ spec: type: object scmProvider: properties: + awsCodeCommit: + properties: + allBranches: + type: boolean + region: + type: string + role: + type: string + tagFilters: + items: + properties: + key: + type: string + value: + type: string + required: + - key + type: object + type: array + type: object azureDevOps: properties: accessTokenRef: @@ -13753,8 +19034,12 @@ spec: type: string group: type: string + includeSharedProjects: + type: boolean includeSubgroups: type: boolean + insecure: + type: boolean tokenRef: properties: key: @@ -13765,6 +19050,8 @@ spec: - key - secretName type: object + topic: + type: string required: - group type: object @@ -13931,6 +19218,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -13940,10 +19230,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13952,10 +19248,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -14089,6 +19434,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -14098,10 +19446,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14110,10 +19464,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -14214,6 +19617,10 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object type: object selector: properties: @@ -14242,6 +19649,36 @@ spec: type: array goTemplate: type: boolean + goTemplateOptions: + items: + type: string + type: array + ignoreApplicationDifferences: + items: + properties: + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + name: + type: string + type: object + type: array + preservedFields: + properties: + annotations: + items: + type: string + type: array + labels: + items: + type: string + type: array + type: object strategy: properties: rollingSync: @@ -14275,6 +19712,13 @@ spec: type: object syncPolicy: properties: + applicationsSync: + enum: + - create-only + - create-update + - create-delete + - sync + type: string preserveResourcesOnDeletion: type: boolean type: object @@ -14438,6 +19882,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -14447,10 +19894,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14459,10 +19912,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -14596,6 +20098,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -14605,10 +20110,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14617,10 +20128,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -14721,6 +20281,8 @@ spec: - metadata - spec type: object + templatePatch: + type: string required: - generators - template @@ -14739,10 +20301,13 @@ spec: type: string status: type: string + step: + type: string required: - application - message - status + - step type: object type: array conditions: @@ -14866,7 +20431,8 @@ spec: properties: name: description: Name is an alternate way of specifying the target - cluster by its symbolic name + cluster by its symbolic name. This must be set if Server is + not set. type: string namespace: description: Namespace specifies the target namespace for the @@ -14874,8 +20440,9 @@ spec: namespace-scoped resources that have not set a value for .metadata.namespace type: string server: - description: Server specifies the URL of the target cluster - and must be set to the Kubernetes control plane API + description: Server specifies the URL of the target cluster's + Kubernetes control plane API. This must be set if Name is + not set. type: string type: object type: array @@ -15112,9 +20679,9 @@ apiVersion: v1 kind: ServiceAccount metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller --- apiVersion: v1 @@ -15173,14 +20740,22 @@ rules: verbs: - create - list +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller rules: - apiGroups: @@ -15280,9 +20855,9 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller roleRef: apiGroup: rbac.authorization.k8s.io @@ -15293,22 +20868,6 @@ subjects: name: argocd-applicationset-controller --- apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - labels: - app.kubernetes.io/component: redis - app.kubernetes.io/name: argocd-redis - app.kubernetes.io/part-of: argocd - name: argocd-redis -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: argocd-redis -subjects: -- kind: ServiceAccount - name: argocd-redis ---- -apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: labels: @@ -15359,16 +20918,22 @@ metadata: --- apiVersion: v1 data: - ssh_known_hosts: |- - bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== - github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== + ssh_known_hosts: | + # This file was automatically generated by hack/update-ssh-known-hosts.sh. DO NOT EDIT + [ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + [ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + [ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= + bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= + bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO + bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M= + github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H - github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= - github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl kind: ConfigMap metadata: labels: @@ -15397,9 +20962,9 @@ apiVersion: v1 kind: Service metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller spec: ports: @@ -15472,9 +21037,9 @@ apiVersion: apps/v1 kind: Deployment metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller spec: selector: @@ -15486,10 +21051,21 @@ spec: app.kubernetes.io/name: argocd-applicationset-controller spec: containers: - - command: - - entrypoint.sh - - argocd-applicationset-controller + - args: + - /usr/local/bin/argocd-applicationset-controller env: + - name: ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_ANNOTATIONS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.global.preserved.annotations + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_LABELS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.global.preserved.labels + name: argocd-cmd-params-cm + optional: true - name: NAMESPACE valueFrom: fieldRef: @@ -15500,12 +21076,6 @@ spec: key: applicationsetcontroller.enable.leader.election name: argocd-cmd-params-cm optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACE - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.namespace - name: argocd-cmd-params-cm - optional: true - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER valueFrom: configMapKeyRef: @@ -15518,6 +21088,12 @@ spec: key: applicationsetcontroller.policy name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.policy.override + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG valueFrom: configMapKeyRef: @@ -15548,10 +21124,64 @@ spec: key: applicationsetcontroller.enable.git.submodule name: argocd-cmd-params-cm optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS valueFrom: configMapKeyRef: - key: applicationsetcontroller.enable.progressive.rollouts + key: applicationsetcontroller.enable.progressive.syncs + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.new.git.file.globbing + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.strict.tls + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.timeout.seconds + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_CONCURRENT_RECONCILIATIONS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.concurrent.reconciliations.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.namespaces + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.scm.root.ca.path + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.allowed.scm.providers + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.scm.providers name: argocd-cmd-params-cm optional: true image: quay.io/argoproj/argocd:latest @@ -15582,6 +21212,8 @@ spec: name: gpg-keyring - mountPath: /tmp name: tmp + - mountPath: /app/config/reposerver/tls + name: argocd-repo-server-tls serviceAccountName: argocd-applicationset-controller volumes: - configMap: @@ -15597,6 +21229,17 @@ spec: name: gpg-keyring - emptyDir: {} name: tmp + - name: argocd-repo-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-repo-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -15636,7 +21279,7 @@ spec: - "" - --appendonly - "no" - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: Always name: redis ports: @@ -15646,6 +21289,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true securityContext: runAsNonRoot: true runAsUser: 999 @@ -15687,10 +21331,8 @@ spec: weight: 5 automountServiceAccountToken: false containers: - - command: - - sh - - -c - - entrypoint.sh argocd-repo-server --redis argocd-redis:6379 + - args: + - /usr/local/bin/argocd-repo-server env: - name: ARGOCD_RECONCILIATION_TIMEOUT valueFrom: @@ -15716,6 +21358,18 @@ spec: key: reposerver.parallelism.limit name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: reposerver.listen.address + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_LISTEN_METRICS_ADDRESS + valueFrom: + configMapKeyRef: + key: reposerver.metrics.listen.address + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_REPO_SERVER_DISABLE_TLS valueFrom: configMapKeyRef: @@ -15776,6 +21430,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: @@ -15806,12 +21472,42 @@ spec: key: reposerver.streamed.manifest.max.extracted.size name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE + valueFrom: + configMapKeyRef: + key: reposerver.helm.manifest.max.extracted.size + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE + valueFrom: + configMapKeyRef: + key: reposerver.disable.helm.manifest.max.extracted.size + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REVISION_CACHE_LOCK_TIMEOUT + valueFrom: + configMapKeyRef: + key: reposerver.revision.cache.lock.timeout + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_GIT_MODULES_ENABLED valueFrom: configMapKeyRef: 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 @@ -15866,7 +21562,7 @@ spec: name: plugins initContainers: - command: - - cp + - /bin/cp - -n - /usr/local/bin/argocd - /var/run/argocd/argocd-cmp-server @@ -15952,8 +21648,8 @@ spec: topologyKey: kubernetes.io/hostname weight: 5 containers: - - command: - - argocd-application-controller + - args: + - /usr/local/bin/argocd-application-controller env: - name: ARGOCD_CONTROLLER_REPLICAS value: "1" @@ -15969,6 +21665,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: @@ -16071,12 +21779,54 @@ 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: key: application.namespaces name: argocd-cmd-params-cm optional: true + - name: ARGOCD_CONTROLLER_SHARDING_ALGORITHM + valueFrom: + configMapKeyRef: + key: controller.sharding.algorithm + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_KUBECTL_PARALLELISM_LIMIT + valueFrom: + configMapKeyRef: + 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 @@ -16202,6 +21952,9 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-applicationset-controller ports: - port: 8081 protocol: TCP diff --git a/manifests/crds/application-crd.yaml b/manifests/crds/application-crd.yaml index d19394e84f8fd..aaf1347f64dfb 100644 --- a/manifests/crds/application-crd.yaml +++ b/manifests/crds/application-crd.yaml @@ -286,8 +286,15 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be + passed to helm template, defined as a map. This takes + precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -302,12 +309,22 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -325,6 +342,10 @@ spec: definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether to + apply common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -333,6 +354,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -548,8 +623,15 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be + passed to helm template, defined as a map. This takes + precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -564,12 +646,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -588,6 +681,10 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -596,6 +693,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -717,7 +868,8 @@ spec: properties: name: description: Name is an alternate way of specifying the target - cluster by its symbolic name + cluster by its symbolic name. This must be set if Server is + not set. type: string namespace: description: Namespace specifies the target namespace for the @@ -725,8 +877,9 @@ spec: namespace-scoped resources that have not set a value for .metadata.namespace type: string server: - description: Server specifies the URL of the target cluster and - must be set to the Kubernetes control plane API + description: Server specifies the URL of the target cluster's + Kubernetes control plane API. This must be set if Name is not + set. type: string type: object ignoreDifferences: @@ -926,8 +1079,15 @@ spec: type: array values: description: Values specifies Helm values to be passed to - helm template, typically defined as a block + helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be passed + to helm template, defined as a map. This takes precedence + over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -942,12 +1102,22 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether to + apply env variables substitution for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -964,6 +1134,10 @@ spec: definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether to apply + common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -972,6 +1146,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize adds + to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas override + specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -1179,8 +1407,15 @@ spec: type: array values: description: Values specifies Helm values to be passed to - helm template, typically defined as a block + helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be passed + to helm template, defined as a map. This takes precedence + over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -1195,12 +1430,22 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -1218,6 +1463,10 @@ spec: definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether to apply + common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -1226,6 +1475,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas override + specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -1318,7 +1621,7 @@ spec: as part of automated sync (default: false)' type: boolean selfHeal: - description: 'SelfHeal specifes whether to revert resources + description: 'SelfHeal specifies whether to revert resources back to their desired state upon modification in the cluster (default: false)' type: boolean @@ -1382,7 +1685,7 @@ spec: conditions items: description: ApplicationCondition contains details about an application - condition, which is usally an error or warning + condition, which is usually an error or warning properties: lastTransitionTime: description: LastTransitionTime is the time the condition was @@ -1401,6 +1704,10 @@ spec: - type type: object type: array + controllerNamespace: + description: ControllerNamespace indicates the namespace in which + the application controller is located + type: string health: description: Health contains information about the application's current health status @@ -1434,6 +1741,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 @@ -1580,8 +1900,15 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be + passed to helm template, defined as a map. This takes + precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -1596,12 +1923,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -1620,6 +1958,10 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -1628,6 +1970,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -1845,8 +2241,16 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. + ValuesObject takes precedence over Values, so use + one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to + be passed to helm template, defined as a map. This + takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -1861,12 +2265,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -1885,6 +2300,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -1893,6 +2313,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -2255,8 +2729,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined as - a block + a block. ValuesObject takes precedence over + Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as a + map. This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -2271,12 +2752,24 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution + for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -2295,6 +2788,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors + or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -2303,6 +2801,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that + Kustomize adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -2536,8 +3088,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined - as a block + as a block. ValuesObject takes precedence + over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as + a map. This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -2554,12 +3113,24 @@ spec: additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution + for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -2578,6 +3149,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies + whether to apply common labels to resource + selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -2586,6 +3162,61 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that + Kustomize adds to all resources + type: string + patches: + description: Patches is a list of Kustomize + patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize + Replicas override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -2719,6 +3350,19 @@ spec: syncResult: description: SyncResult is the result of a Sync operation properties: + managedNamespaceMetadata: + description: ManagedNamespaceMetadata contains the current + sync state of managed namespace metadata + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object resources: description: Resources contains a list of sync result items for each individual resource in a sync operation @@ -2921,8 +3565,16 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. + ValuesObject takes precedence over Values, so use + one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to + be passed to helm template, defined as a map. This + takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -2937,12 +3589,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -2961,6 +3624,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -2969,6 +3637,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -3197,8 +3919,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined as - a block + a block. ValuesObject takes precedence over Values, + so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as a map. + This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -3213,12 +3942,24 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution for + annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -3237,6 +3978,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -3245,6 +3991,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -3427,7 +4227,8 @@ spec: properties: name: description: Name is an alternate way of specifying the - target cluster by its symbolic name + target cluster by its symbolic name. This must be set + if Server is not set. type: string namespace: description: Namespace specifies the target namespace @@ -3436,10 +4237,47 @@ spec: not set a value for .metadata.namespace type: string server: - description: Server specifies the URL of the target cluster - and must be set to the Kubernetes control plane API + description: Server specifies the URL of the target cluster's + Kubernetes control plane API. This must be set if Name + is not set. type: string type: object + ignoreDifferences: + description: IgnoreDifferences is a reference to the application's + ignored differences used for comparison + items: + description: ResourceIgnoreDifferences contains resource + filter and list of json paths which should be ignored + during comparison with live state. + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + description: ManagedFieldsManagers is a list of trusted + managers. Fields mutated by those managers will take + precedence over the desired state defined in the SCM + and won't be displayed in diffs + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array source: description: Source is a reference to the application's source used for comparison @@ -3578,8 +4416,16 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. + ValuesObject takes precedence over Values, so use + one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to + be passed to helm template, defined as a map. This + takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -3594,12 +4440,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -3618,6 +4475,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -3626,6 +4488,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -3854,8 +4770,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined as - a block + a block. ValuesObject takes precedence over Values, + so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as a map. + This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -3870,12 +4793,24 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution for + annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -3894,6 +4829,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -3902,6 +4842,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests diff --git a/manifests/crds/applicationset-crd.yaml b/manifests/crds/applicationset-crd.yaml index 7f8c3e0251972..2668052f431a0 100644 --- a/manifests/crds/applicationset-crd.yaml +++ b/manifests/crds/applicationset-crd.yaml @@ -29,6 +29,8 @@ spec: type: object spec: properties: + applyNestedSelectors: + type: boolean generators: items: properties: @@ -224,6 +226,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -233,10 +238,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -245,10 +256,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -382,6 +442,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -391,10 +454,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -403,10 +472,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -699,6 +817,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -708,10 +829,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -720,10 +847,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -857,6 +1033,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -866,10 +1045,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -878,10 +1063,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -1178,6 +1412,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -1187,10 +1424,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -1199,10 +1442,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -1336,6 +1628,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -1345,10 +1640,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -1357,10 +1658,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -1461,6 +1811,10 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object required: - repoURL - revision @@ -1471,6 +1825,8 @@ spec: items: x-kubernetes-preserve-unknown-fields: true type: array + elementsYaml: + type: string template: properties: metadata: @@ -1631,6 +1987,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -1640,10 +1999,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -1652,36 +2017,85 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string - version: + namespace: type: string - type: object - path: - type: string - plugin: - properties: - env: + patches: items: properties: - name: + options: + additionalProperties: + type: boolean + type: object + patch: type: string - value: + path: type: string - required: - - name - - value - type: object - type: array - name: - type: string - parameters: - items: - properties: - array: - items: + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: type: string type: array map: @@ -1789,6 +2203,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -1798,10 +2215,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -1810,10 +2233,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -1914,8 +2386,6 @@ spec: - metadata - spec type: object - required: - - elements type: object matrix: properties: @@ -2114,6 +2584,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -2123,10 +2596,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -2135,10 +2614,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -2272,6 +2800,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -2281,10 +2812,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -2293,10 +2830,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -2589,6 +3175,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -2598,10 +3187,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -2610,10 +3205,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -2747,6 +3391,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -2756,10 +3403,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -2768,10 +3421,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -3068,6 +3770,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -3077,10 +3782,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -3089,36 +3800,85 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string - version: + namespace: type: string - type: object - path: - type: string - plugin: - properties: - env: + patches: items: properties: - name: + options: + additionalProperties: + type: boolean + type: object + patch: type: string - value: + path: type: string - required: - - name - - value - type: object - type: array - name: - type: string - parameters: - items: - properties: - array: - items: + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: type: string type: array map: @@ -3226,6 +3986,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -3235,10 +3998,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -3247,10 +4016,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -3351,6 +4169,10 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object required: - repoURL - revision @@ -3361,6 +4183,8 @@ spec: items: x-kubernetes-preserve-unknown-fields: true type: array + elementsYaml: + type: string template: properties: metadata: @@ -3521,6 +4345,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -3530,10 +4357,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -3542,10 +4375,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -3679,6 +4561,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -3688,10 +4573,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -3700,10 +4591,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -3804,153 +4744,49 @@ spec: - metadata - spec type: object - required: - - elements type: object matrix: x-kubernetes-preserve-unknown-fields: true merge: x-kubernetes-preserve-unknown-fields: true - pullRequest: + plugin: properties: - bitbucketServer: + configMapRef: properties: - api: - type: string - basicAuth: - properties: - passwordRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - username: - type: string - required: - - passwordRef - - username - type: object - project: - type: string - repo: + name: type: string required: - - api - - project - - repo + - name type: object - filters: - items: - properties: - branchMatch: - type: string - type: object - type: array - gitea: + input: properties: - api: - type: string - insecure: - type: boolean - owner: - type: string - repo: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName + parameters: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true type: object - required: - - api - - owner - - repo type: object - github: + requeueAfterSeconds: + format: int64 + type: integer + template: properties: - api: - type: string - appSecretName: - type: string - labels: - items: - type: string - type: array - owner: - type: string - repo: - type: string - tokenRef: + metadata: properties: - key: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - owner - - repo - type: object - gitlab: - properties: - api: - type: string - labels: - items: - type: string - type: array - project: - type: string - pullRequestState: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - project - type: object - requeueAfterSeconds: - format: int64 - type: integer - template: - properties: - metadata: - properties: - annotations: - additionalProperties: - type: string - type: object - finalizers: - items: - type: string - type: array - labels: - additionalProperties: - type: string - type: object - name: - type: string - namespace: + namespace: type: string type: object spec: @@ -4092,6 +4928,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4101,10 +4940,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4113,10 +4958,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4250,6 +5144,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4259,10 +5156,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4271,10 +5174,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4375,12 +5327,30 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object + required: + - configMapRef type: object - scmProvider: + pullRequest: properties: - azureDevOps: + azuredevops: properties: - accessTokenRef: + api: + type: string + labels: + items: + type: string + type: array + organization: + type: string + project: + type: string + repo: + type: string + tokenRef: properties: key: type: string @@ -4390,46 +5360,58 @@ spec: - key - secretName type: object - allBranches: - type: boolean - api: - type: string - organization: - type: string - teamProject: - type: string required: - - accessTokenRef - organization - - teamProject + - project + - repo type: object bitbucket: properties: - allBranches: - type: boolean - appPasswordRef: + api: + type: string + basicAuth: properties: - key: - type: string - secretName: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: type: string required: - - key - - secretName + - passwordRef + - username + type: object + bearerToken: + properties: + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - tokenRef type: object owner: type: string - user: + repo: type: string required: - - appPasswordRef - owner - - user + - repo type: object bitbucketServer: properties: - allBranches: - type: boolean api: type: string basicAuth: @@ -4452,41 +5434,32 @@ spec: type: object project: type: string + repo: + type: string required: - api - project + - repo type: object - cloneProtocol: - type: string filters: items: properties: branchMatch: type: string - labelMatch: - type: string - pathsDoNotExist: - items: - type: string - type: array - pathsExist: - items: - type: string - type: array - repositoryMatch: + targetBranchMatch: type: string type: object type: array gitea: properties: - allBranches: - type: boolean api: type: string insecure: type: boolean owner: type: string + repo: + type: string tokenRef: properties: key: @@ -4500,16 +5473,21 @@ spec: required: - api - owner + - repo type: object github: properties: - allBranches: - type: boolean api: type: string appSecretName: type: string - organization: + labels: + items: + type: string + type: array + owner: + type: string + repo: type: string tokenRef: properties: @@ -4522,18 +5500,23 @@ spec: - secretName type: object required: - - organization + - owner + - repo type: object gitlab: properties: - allBranches: - type: boolean api: type: string - group: - type: string - includeSubgroups: + insecure: type: boolean + labels: + items: + type: string + type: array + project: + type: string + pullRequestState: + type: string tokenRef: properties: key: @@ -4545,7 +5528,7 @@ spec: - secretName type: object required: - - group + - project type: object requeueAfterSeconds: format: int64 @@ -4710,6 +5693,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4719,10 +5705,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4731,10 +5723,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4868,6 +5909,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4877,10 +5921,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4889,10 +5939,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4994,511 +6093,203 @@ spec: - spec type: object type: object - selector: + scmProvider: properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - type: string - values: - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - type: object - type: object - type: object - type: array - template: - properties: - metadata: - properties: - annotations: - additionalProperties: - type: string - type: object - finalizers: - items: - type: string - type: array - labels: - additionalProperties: - type: string - type: object - name: - type: string - namespace: - type: string - type: object - spec: - properties: - destination: - properties: - name: - type: string - namespace: - type: string - server: - type: string - type: object - ignoreDifferences: - items: + awsCodeCommit: properties: - group: + allBranches: + type: boolean + region: type: string - jqPathExpressions: - items: - type: string - type: array - jsonPointers: - items: - type: string - type: array - kind: + role: type: string - managedFieldsManagers: + tagFilters: items: - type: string + properties: + key: + type: string + value: + type: string + required: + - key + type: object type: array - name: + type: object + azureDevOps: + properties: + accessTokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + allBranches: + type: boolean + api: type: string - namespace: + organization: + type: string + teamProject: type: string required: - - kind + - accessTokenRef + - organization + - teamProject type: object - type: array - info: - items: + bitbucket: properties: - name: + allBranches: + type: boolean + appPasswordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + owner: type: string - value: + user: type: string required: - - name - - value + - appPasswordRef + - owner + - user type: object - type: array - project: - type: string - revisionHistoryLimit: - format: int64 - type: integer - source: - properties: - chart: - type: string - directory: + bitbucketServer: + properties: + allBranches: + type: boolean + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + project: + type: string + required: + - api + - project + type: object + cloneProtocol: + type: string + filters: + items: properties: - exclude: + branchMatch: type: string - include: + labelMatch: type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean - type: object - helm: - properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: - type: boolean - valueFiles: + pathsDoNotExist: items: type: string type: array - values: - type: string - version: - type: string - type: object - kustomize: - properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: - type: boolean - images: + pathsExist: items: type: string type: array - namePrefix: - type: string - nameSuffix: - type: string - version: - type: string - type: object - path: - type: string - plugin: - properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - name: + repositoryMatch: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array type: object - ref: - type: string - repoURL: - type: string - targetRevision: - type: string - required: - - repoURL - type: object - sources: - items: + type: array + gitea: properties: - chart: + allBranches: + type: boolean + api: type: string - directory: + insecure: + type: boolean + owner: + type: string + tokenRef: properties: - exclude: + key: type: string - include: + secretName: type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean + required: + - key + - secretName type: object - helm: + required: + - api + - owner + type: object + github: + properties: + allBranches: + type: boolean + api: + type: string + appSecretName: + type: string + organization: + type: string + tokenRef: properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: - type: boolean - valueFiles: - items: - type: string - type: array - values: + key: type: string - version: + secretName: type: string + required: + - key + - secretName type: object - kustomize: - properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: - type: boolean - images: - items: - type: string - type: array - namePrefix: - type: string - nameSuffix: - type: string - version: - type: string - type: object - path: + required: + - organization + type: object + gitlab: + properties: + allBranches: + type: boolean + api: type: string - plugin: + group: + type: string + includeSharedProjects: + type: boolean + includeSubgroups: + type: boolean + insecure: + type: boolean + tokenRef: properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - name: + key: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array + secretName: + type: string + required: + - key + - secretName type: object - ref: - type: string - repoURL: - type: string - targetRevision: + topic: type: string required: - - repoURL - type: object - type: array - syncPolicy: - properties: - automated: - properties: - allowEmpty: - type: boolean - prune: - type: boolean - selfHeal: - type: boolean - type: object - managedNamespaceMetadata: - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - retry: - properties: - backoff: - properties: - duration: - type: string - factor: - format: int64 - type: integer - maxDuration: - type: string - type: object - limit: - format: int64 - type: integer - type: object - syncOptions: - items: - type: string - type: array - type: object - required: - - destination - - project - type: object - required: - - metadata - - spec - type: object - required: - - generators - type: object - merge: - properties: - generators: - items: - properties: - clusterDecisionResource: - properties: - configMapRef: - type: string - labelSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - type: string - values: - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - type: object + - group type: object - name: - type: string requeueAfterSeconds: format: int64 type: integer @@ -5662,6 +6453,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5671,10 +6465,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5683,10 +6483,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5820,6 +6669,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5829,10 +6681,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5841,10 +6699,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5949,94 +6856,499 @@ spec: additionalProperties: type: string type: object - required: - - configMapRef type: object - clusters: + selector: properties: - selector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - type: string - values: - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: + matchExpressions: + items: + properties: + key: type: string - type: object + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string type: object - template: + type: object + type: object + type: array + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: properties: - metadata: - properties: - annotations: - additionalProperties: - type: string + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string type: object - finalizers: - items: - type: string - type: array - labels: - additionalProperties: - type: string + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string type: object - name: + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: type: string - namespace: + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: type: string - type: object - spec: - properties: - destination: + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: properties: - name: - type: string - namespace: + options: + additionalProperties: + type: boolean + type: object + patch: type: string - server: + path: type: string - type: object - ignoreDifferences: - items: - properties: - group: - type: string - jqPathExpressions: - items: + target: + properties: + annotationSelector: type: string - type: array - jsonPointers: - items: + group: type: string - type: array - kind: - type: string - managedFieldsManagers: - items: + kind: type: string - type: array - name: + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: type: string - namespace: + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: type: string required: - - kind + - count + - name type: object type: array - info: + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: items: properties: name: @@ -6048,38 +7360,230 @@ spec: - value type: object type: array - project: + name: type: string - revisionHistoryLimit: - format: int64 - type: integer - source: - properties: - chart: - type: string - directory: - properties: - exclude: + parameters: + items: + properties: + array: + items: type: string - include: + type: array + map: + additionalProperties: type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + required: + - generators + type: object + merge: + properties: + generators: + items: + properties: + clusterDecisionResource: + properties: + configMapRef: + type: string + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + name: + type: string + requeueAfterSeconds: + format: int64 + type: integer + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: items: type: string type: array @@ -6137,6 +7641,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6146,10 +7653,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6158,10 +7671,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -6295,6 +7857,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6304,10 +7869,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6316,14 +7887,63 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string - version: + namespace: type: string - type: object - path: + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: type: string plugin: properties: @@ -6424,38 +8044,34 @@ spec: additionalProperties: type: string type: object + required: + - configMapRef type: object - git: + clusters: properties: - directories: - items: - properties: - exclude: - type: boolean - path: - type: string - required: - - path - type: object - type: array - files: - items: - properties: - path: + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: type: string - required: - - path - type: object - type: array - pathParamPrefix: - type: string - repoURL: - type: string - requeueAfterSeconds: - format: int64 - type: integer - revision: - type: string + type: object + type: object template: properties: metadata: @@ -6616,6 +8232,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6625,10 +8244,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6637,10 +8262,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -6774,6 +8448,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6783,10 +8460,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6795,10 +8478,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -6899,16 +8631,42 @@ spec: - metadata - spec type: object - required: - - repoURL - - revision + values: + additionalProperties: + type: string + type: object type: object - list: + git: properties: - elements: + directories: items: - x-kubernetes-preserve-unknown-fields: true + properties: + exclude: + type: boolean + path: + type: string + required: + - path + type: object type: array + files: + items: + properties: + path: + type: string + required: + - path + type: object + type: array + pathParamPrefix: + type: string + repoURL: + type: string + requeueAfterSeconds: + format: int64 + type: integer + revision: + type: string template: properties: metadata: @@ -7069,6 +8827,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7078,10 +8839,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7090,10 +8857,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7227,6 +9043,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7236,10 +9055,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7248,32 +9073,81 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string - version: + namespace: type: string - type: object - path: - type: string - plugin: - properties: - env: + patches: items: properties: - name: + options: + additionalProperties: + type: boolean + type: object + patch: type: string - value: + path: type: string - required: - - name - - value - type: object - type: array - name: - type: string - parameters: + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: items: properties: array: @@ -7352,134 +9226,22 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object required: - - elements + - repoURL + - revision type: object - matrix: - x-kubernetes-preserve-unknown-fields: true - merge: - x-kubernetes-preserve-unknown-fields: true - pullRequest: + list: properties: - bitbucketServer: - properties: - api: - type: string - basicAuth: - properties: - passwordRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - username: - type: string - required: - - passwordRef - - username - type: object - project: - type: string - repo: - type: string - required: - - api - - project - - repo - type: object - filters: + elements: items: - properties: - branchMatch: - type: string - type: object + x-kubernetes-preserve-unknown-fields: true type: array - gitea: - properties: - api: - type: string - insecure: - type: boolean - owner: - type: string - repo: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - api - - owner - - repo - type: object - github: - properties: - api: - type: string - appSecretName: - type: string - labels: - items: - type: string - type: array - owner: - type: string - repo: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - owner - - repo - type: object - gitlab: - properties: - api: - type: string - labels: - items: - type: string - type: array - project: - type: string - pullRequestState: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - project - type: object - requeueAfterSeconds: - format: int64 - type: integer + elementsYaml: + type: string template: properties: metadata: @@ -7640,6 +9402,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7649,10 +9414,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7661,10 +9432,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7798,6 +9618,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7807,10 +9630,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7819,10 +9648,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7924,176 +9802,25 @@ spec: - spec type: object type: object - scmProvider: + matrix: + x-kubernetes-preserve-unknown-fields: true + merge: + x-kubernetes-preserve-unknown-fields: true + plugin: properties: - azureDevOps: + configMapRef: properties: - accessTokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - allBranches: - type: boolean - api: - type: string - organization: - type: string - teamProject: - type: string - required: - - accessTokenRef - - organization - - teamProject - type: object - bitbucket: - properties: - allBranches: - type: boolean - appPasswordRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - owner: - type: string - user: - type: string - required: - - appPasswordRef - - owner - - user - type: object - bitbucketServer: - properties: - allBranches: - type: boolean - api: - type: string - basicAuth: - properties: - passwordRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - username: - type: string - required: - - passwordRef - - username - type: object - project: - type: string - required: - - api - - project - type: object - cloneProtocol: - type: string - filters: - items: - properties: - branchMatch: - type: string - labelMatch: - type: string - pathsDoNotExist: - items: - type: string - type: array - pathsExist: - items: - type: string - type: array - repositoryMatch: - type: string - type: object - type: array - gitea: - properties: - allBranches: - type: boolean - api: - type: string - insecure: - type: boolean - owner: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - api - - owner - type: object - github: - properties: - allBranches: - type: boolean - api: - type: string - appSecretName: - type: string - organization: + name: type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object required: - - organization + - name type: object - gitlab: + input: properties: - allBranches: - type: boolean - api: - type: string - group: - type: string - includeSubgroups: - type: boolean - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName + parameters: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true type: object - required: - - group type: object requeueAfterSeconds: format: int64 @@ -8222,355 +9949,2582 @@ spec: recurse: type: boolean type: object - helm: + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + required: + - configMapRef + type: object + pullRequest: + properties: + azuredevops: + properties: + api: + type: string + labels: + items: + type: string + type: array + organization: + type: string + project: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - organization + - project + - repo + type: object + bitbucket: + properties: + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + bearerToken: + properties: + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - tokenRef + type: object + owner: + type: string + repo: + type: string + required: + - owner + - repo + type: object + bitbucketServer: + properties: + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + project: + type: string + repo: + type: string + required: + - api + - project + - repo + type: object + filters: + items: + properties: + branchMatch: + type: string + targetBranchMatch: + type: string + type: object + type: array + gitea: + properties: + api: + type: string + insecure: + type: boolean + owner: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - api + - owner + - repo + type: object + github: + properties: + api: + type: string + appSecretName: + type: string + labels: + items: + type: string + type: array + owner: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - owner + - repo + type: object + gitlab: + properties: + api: + type: string + insecure: + type: boolean + labels: + items: + type: string + type: array + project: + type: string + pullRequestState: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - project + type: object + requeueAfterSeconds: + format: int64 + type: integer + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + type: object + scmProvider: + properties: + awsCodeCommit: + properties: + allBranches: + type: boolean + region: + type: string + role: + type: string + tagFilters: + items: + properties: + key: + type: string + value: + type: string + required: + - key + type: object + type: array + type: object + azureDevOps: + properties: + accessTokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + allBranches: + type: boolean + api: + type: string + organization: + type: string + teamProject: + type: string + required: + - accessTokenRef + - organization + - teamProject + type: object + bitbucket: + properties: + allBranches: + type: boolean + appPasswordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + owner: + type: string + user: + type: string + required: + - appPasswordRef + - owner + - user + type: object + bitbucketServer: + properties: + allBranches: + type: boolean + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + project: + type: string + required: + - api + - project + type: object + cloneProtocol: + type: string + filters: + items: + properties: + branchMatch: + type: string + labelMatch: + type: string + pathsDoNotExist: + items: + type: string + type: array + pathsExist: + items: + type: string + type: array + repositoryMatch: + type: string + type: object + type: array + gitea: + properties: + allBranches: + type: boolean + api: + type: string + insecure: + type: boolean + owner: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - api + - owner + type: object + github: + properties: + allBranches: + type: boolean + api: + type: string + appSecretName: + type: string + organization: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - organization + type: object + gitlab: + properties: + allBranches: + type: boolean + api: + type: string + group: + type: string + includeSharedProjects: + type: boolean + includeSubgroups: + type: boolean + insecure: + type: boolean + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + topic: + type: string + required: + - group + type: object + requeueAfterSeconds: + format: int64 + type: integer + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + type: array + mergeKeys: + items: + type: string + type: array + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: + annotationSelector: type: string - skipCrds: - type: boolean - valueFiles: - items: - type: string - type: array - values: + group: type: string - version: + kind: type: string - type: object - kustomize: - properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: - type: boolean - images: - items: - type: string - type: array - namePrefix: + labelSelector: type: string - nameSuffix: + name: type: string - version: + namespace: type: string - type: object - path: - type: string - plugin: - properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - name: + version: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array type: object - ref: + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: type: string - repoURL: + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: type: string - targetRevision: + value: type: string required: - - repoURL + - name + - value type: object - sources: - items: - properties: - chart: + type: array + name: + type: string + parameters: + items: + properties: + array: + items: type: string - directory: - properties: - exclude: - type: string - include: - type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean - type: object - helm: + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: - type: boolean - valueFiles: - items: - type: string - type: array - values: + code: + type: boolean + name: type: string - version: + value: type: string + required: + - name + - value type: object - kustomize: + type: array + libs: + items: + type: string + type: array + tlas: + items: properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: + code: type: boolean - images: - items: - type: string - type: array - namePrefix: - type: string - nameSuffix: + name: type: string - version: + value: type: string + required: + - name + - value type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string path: type: string - plugin: + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string name: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array + namespace: + type: string + version: + type: string type: object - ref: + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: type: string - repoURL: + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: type: string - targetRevision: + value: type: string required: - - repoURL + - name + - value type: object type: array - syncPolicy: - properties: - automated: - properties: - allowEmpty: - type: boolean - prune: - type: boolean - selfHeal: - type: boolean - type: object - managedNamespaceMetadata: - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - retry: - properties: - backoff: - properties: - duration: - type: string - factor: - format: int64 - type: integer - maxDuration: - type: string - type: object - limit: - format: int64 - type: integer - type: object - syncOptions: - items: + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: type: string - type: array - type: object - required: - - destination - - project + string: + type: string + type: object + type: array type: object - required: - - metadata - - spec + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL type: object - type: object - selector: - properties: - matchExpressions: - items: + type: array + syncPolicy: + properties: + automated: properties: - key: - type: string - operator: - type: string - values: - items: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: type: string - type: array - required: - - key - - operator + type: object + labels: + additionalProperties: + type: string + type: object type: object - type: array - matchLabels: - additionalProperties: - type: string - type: object - type: object - type: object - type: array - mergeKeys: - items: - type: string - type: array + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + required: + - generators + - mergeKeys + type: object + plugin: + properties: + configMapRef: + properties: + name: + type: string + required: + - name + type: object + input: + properties: + parameters: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + requeueAfterSeconds: + format: int64 + type: integer template: properties: metadata: @@ -8731,6 +12685,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8740,10 +12697,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8752,10 +12715,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -8889,6 +12901,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8898,10 +12913,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8910,10 +12931,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -9014,12 +13084,89 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object required: - - generators - - mergeKeys + - configMapRef type: object pullRequest: properties: + azuredevops: + properties: + api: + type: string + labels: + items: + type: string + type: array + organization: + type: string + project: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - organization + - project + - repo + type: object + bitbucket: + properties: + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + bearerToken: + properties: + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - tokenRef + type: object + owner: + type: string + repo: + type: string + required: + - owner + - repo + type: object bitbucketServer: properties: api: @@ -9056,6 +13203,8 @@ spec: properties: branchMatch: type: string + targetBranchMatch: + type: string type: object type: array gitea: @@ -9115,6 +13264,8 @@ spec: properties: api: type: string + insecure: + type: boolean labels: items: type: string @@ -9299,6 +13450,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -9308,10 +13462,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string - type: object + type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9320,10 +13480,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -9457,6 +13666,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -9466,10 +13678,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9478,10 +13696,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -9585,6 +13852,26 @@ spec: type: object scmProvider: properties: + awsCodeCommit: + properties: + allBranches: + type: boolean + region: + type: string + role: + type: string + tagFilters: + items: + properties: + key: + type: string + value: + type: string + required: + - key + type: object + type: array + type: object azureDevOps: properties: accessTokenRef: @@ -9739,8 +14026,12 @@ spec: type: string group: type: string + includeSharedProjects: + type: boolean includeSubgroups: type: boolean + insecure: + type: boolean tokenRef: properties: key: @@ -9751,6 +14042,8 @@ spec: - key - secretName type: object + topic: + type: string required: - group type: object @@ -9917,6 +14210,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -9926,10 +14222,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9938,10 +14240,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10075,6 +14426,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10084,10 +14438,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10096,10 +14456,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10200,6 +14609,10 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object type: object selector: properties: @@ -10228,6 +14641,36 @@ spec: type: array goTemplate: type: boolean + goTemplateOptions: + items: + type: string + type: array + ignoreApplicationDifferences: + items: + properties: + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + name: + type: string + type: object + type: array + preservedFields: + properties: + annotations: + items: + type: string + type: array + labels: + items: + type: string + type: array + type: object strategy: properties: rollingSync: @@ -10261,6 +14704,13 @@ spec: type: object syncPolicy: properties: + applicationsSync: + enum: + - create-only + - create-update + - create-delete + - sync + type: string preserveResourcesOnDeletion: type: boolean type: object @@ -10424,6 +14874,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10433,10 +14886,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10445,10 +14904,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10582,6 +15090,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10591,10 +15102,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10603,10 +15120,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10707,6 +15273,8 @@ spec: - metadata - spec type: object + templatePatch: + type: string required: - generators - template @@ -10725,10 +15293,13 @@ spec: type: string status: type: string + step: + type: string required: - application - message - status + - step type: object type: array conditions: diff --git a/manifests/crds/appproject-crd.yaml b/manifests/crds/appproject-crd.yaml index 335decfc564df..989b3004892f6 100644 --- a/manifests/crds/appproject-crd.yaml +++ b/manifests/crds/appproject-crd.yaml @@ -88,7 +88,8 @@ spec: properties: name: description: Name is an alternate way of specifying the target - cluster by its symbolic name + cluster by its symbolic name. This must be set if Server is + not set. type: string namespace: description: Namespace specifies the target namespace for the @@ -96,8 +97,9 @@ spec: namespace-scoped resources that have not set a value for .metadata.namespace type: string server: - description: Server specifies the URL of the target cluster - and must be set to the Kubernetes control plane API + description: Server specifies the URL of the target cluster's + Kubernetes control plane API. This must be set if Name is + not set. type: string type: object type: array diff --git a/manifests/ha/base/controller-deployment/argocd-application-controller-statefulset.yaml b/manifests/ha/base/controller-deployment/argocd-application-controller-statefulset.yaml new file mode 100644 index 0000000000000..10e4ea2ac7e3e --- /dev/null +++ b/manifests/ha/base/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/ha/base/controller-deployment/argocd-cmd-params-cm.yaml b/manifests/ha/base/controller-deployment/argocd-cmd-params-cm.yaml new file mode 100644 index 0000000000000..5752543cc1af3 --- /dev/null +++ b/manifests/ha/base/controller-deployment/argocd-cmd-params-cm.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cmd-params-cm +data: + redis.server: argocd-redis-ha-haproxy:6379 diff --git a/manifests/ha/base/controller-deployment/argocd-repo-server-deployment.yaml b/manifests/ha/base/controller-deployment/argocd-repo-server-deployment.yaml new file mode 100644 index 0000000000000..b237cf6c13b24 --- /dev/null +++ b/manifests/ha/base/controller-deployment/argocd-repo-server-deployment.yaml @@ -0,0 +1,26 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: argocd-repo-server +spec: + replicas: 2 + template: + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: argocd-repo-server + topologyKey: kubernetes.io/hostname + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/name: argocd-repo-server + topologyKey: topology.kubernetes.io/zone + containers: + - name: argocd-repo-server + args: + - /usr/local/bin/argocd-repo-server diff --git a/manifests/ha/base/controller-deployment/argocd-server-deployment.yaml b/manifests/ha/base/controller-deployment/argocd-server-deployment.yaml new file mode 100644 index 0000000000000..49eb31b1b0f29 --- /dev/null +++ b/manifests/ha/base/controller-deployment/argocd-server-deployment.yaml @@ -0,0 +1,29 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: argocd-server +spec: + replicas: 2 + template: + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + app.kubernetes.io/name: argocd-server + topologyKey: kubernetes.io/hostname + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/name: argocd-server + topologyKey: topology.kubernetes.io/zone + containers: + - name: argocd-server + env: + - name: ARGOCD_API_SERVER_REPLICAS + value: '2' + args: + - /usr/local/bin/argocd-server diff --git a/manifests/ha/base/controller-deployment/kustomization.yaml b/manifests/ha/base/controller-deployment/kustomization.yaml new file mode 100644 index 0000000000000..e98bd250d699e --- /dev/null +++ b/manifests/ha/base/controller-deployment/kustomization.yaml @@ -0,0 +1,22 @@ +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-cmd-params-cm.yaml + +images: +- name: quay.io/argoproj/argocd + newName: quay.io/argoproj/argocd + newTag: latest +resources: +- ../../../base/application-controller-deployment +- ../../../base/applicationset-controller +- ../../../base/dex +- ../../../base/repo-server +- ../../../base/server +- ../../../base/config +- ../../../base/notification +- ../redis-ha diff --git a/manifests/ha/base/kustomization.yaml b/manifests/ha/base/kustomization.yaml index c8f8e9e8f5b9b..ae40b96e8657e 100644 --- a/manifests/ha/base/kustomization.yaml +++ b/manifests/ha/base/kustomization.yaml @@ -2,10 +2,11 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -patchesStrategicMerge: -- overlays/argocd-repo-server-deployment.yaml -- overlays/argocd-server-deployment.yaml -- overlays/argocd-application-controller-statefulset.yaml +patches: +- path: overlays/argocd-repo-server-deployment.yaml +- path: overlays/argocd-server-deployment.yaml +- path: overlays/argocd-application-controller-statefulset.yaml +- path: overlays/argocd-cmd-params-cm.yaml images: diff --git a/manifests/ha/base/overlays/argocd-application-controller-statefulset.yaml b/manifests/ha/base/overlays/argocd-application-controller-statefulset.yaml index 07b5c252c29cd..c7e5e0b8e1131 100644 --- a/manifests/ha/base/overlays/argocd-application-controller-statefulset.yaml +++ b/manifests/ha/base/overlays/argocd-application-controller-statefulset.yaml @@ -7,7 +7,5 @@ spec: spec: containers: - name: argocd-application-controller - command: - - argocd-application-controller - - --redis - - "argocd-redis-ha-haproxy:6379" + args: + - /usr/local/bin/argocd-application-controller \ No newline at end of file diff --git a/manifests/ha/base/overlays/argocd-cmd-params-cm.yaml b/manifests/ha/base/overlays/argocd-cmd-params-cm.yaml new file mode 100644 index 0000000000000..5752543cc1af3 --- /dev/null +++ b/manifests/ha/base/overlays/argocd-cmd-params-cm.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cmd-params-cm +data: + redis.server: argocd-redis-ha-haproxy:6379 diff --git a/manifests/ha/base/overlays/argocd-repo-server-deployment.yaml b/manifests/ha/base/overlays/argocd-repo-server-deployment.yaml index 496bb136f602a..b237cf6c13b24 100644 --- a/manifests/ha/base/overlays/argocd-repo-server-deployment.yaml +++ b/manifests/ha/base/overlays/argocd-repo-server-deployment.yaml @@ -19,11 +19,8 @@ spec: labelSelector: matchLabels: app.kubernetes.io/name: argocd-repo-server - topologyKey: failure-domain.beta.kubernetes.io/zone + topologyKey: topology.kubernetes.io/zone containers: - name: argocd-repo-server - command: - - entrypoint.sh - - argocd-repo-server - - --redis - - "argocd-redis-ha-haproxy:6379" + args: + - /usr/local/bin/argocd-repo-server diff --git a/manifests/ha/base/overlays/argocd-server-deployment.yaml b/manifests/ha/base/overlays/argocd-server-deployment.yaml index 0b09752afa3a0..49eb31b1b0f29 100644 --- a/manifests/ha/base/overlays/argocd-server-deployment.yaml +++ b/manifests/ha/base/overlays/argocd-server-deployment.yaml @@ -19,13 +19,11 @@ spec: labelSelector: matchLabels: app.kubernetes.io/name: argocd-server - topologyKey: failure-domain.beta.kubernetes.io/zone + topologyKey: topology.kubernetes.io/zone containers: - name: argocd-server env: - name: ARGOCD_API_SERVER_REPLICAS value: '2' - command: - - argocd-server - - --redis - - "argocd-redis-ha-haproxy:6379" + args: + - /usr/local/bin/argocd-server diff --git a/manifests/ha/base/redis-ha/chart/upstream.yaml b/manifests/ha/base/redis-ha/chart/upstream.yaml index cd890ba33dc4c..1d0e4b3c247f8 100644 --- a/manifests/ha/base/redis-ha/chart/upstream.yaml +++ b/manifests/ha/base/redis-ha/chart/upstream.yaml @@ -686,6 +686,13 @@ data: server R1 argocd-redis-ha-announce-1:6379 check inter 3s fall 1 rise 1 use-server R2 if { srv_is_up(R2) } { nbsrv(check_if_redis_is_master_2) ge 2 } server R2 argocd-redis-ha-announce-2:6379 check inter 3s fall 1 rise 1 + frontend stats + mode http + bind :9101 + http-request use-service prometheus-exporter if { path /metrics } + stats enable + stats uri /stats + stats refresh 10s haproxy_init.sh: | HAPROXY_CONF=/data/haproxy.cfg cp /readonly/haproxy.cfg "$HAPROXY_CONF" @@ -1015,6 +1022,10 @@ spec: port: 6379 protocol: TCP targetPort: redis + - name: http-exporter-port + port: 9101 + protocol: TCP + targetPort: metrics-port selector: release: argocd app: redis-ha-haproxy @@ -1047,7 +1058,10 @@ spec: release: argocd revision: "1" annotations: - checksum/config: 718bbb277da8610063a7c0fd810984577c2e8ab215815a71211dfa6e20f67321 + prometheus.io/port: "9101" + prometheus.io/scrape: "true" + prometheus.io/path: "/metrics" + checksum/config: 492a6adabb741e0cee39be9aa5155c41a4456629f862d0006a2d892dbecfbcae spec: # Needed when using unmodified rbac-setup.yml @@ -1071,7 +1085,7 @@ spec: topologyKey: kubernetes.io/hostname initContainers: - name: config-init - image: haproxy:2.6.2-alpine + image: haproxy:2.6.14-alpine imagePullPolicy: IfNotPresent resources: {} @@ -1080,7 +1094,13 @@ spec: args: - /readonly/haproxy_init.sh securityContext: - null + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault volumeMounts: - name: config-volume mountPath: /readonly @@ -1089,10 +1109,16 @@ spec: mountPath: /data containers: - name: haproxy - image: haproxy:2.6.2-alpine + image: haproxy:2.6.14-alpine imagePullPolicy: IfNotPresent securityContext: - null + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault livenessProbe: httpGet: path: /healthz @@ -1108,6 +1134,8 @@ spec: ports: - name: redis containerPort: 6379 + - name: metrics-port + containerPort: 9101 resources: {} volumeMounts: @@ -1179,7 +1207,7 @@ spec: automountServiceAccountToken: false initContainers: - name: config-init - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent resources: {} @@ -1188,7 +1216,14 @@ spec: args: - /readonly-config/init.sh securityContext: - null + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault env: - name: SENTINEL_ID_0 value: 3c0d9c0320bb34888c2df5757c718ce6ca992ce6 @@ -1206,14 +1241,21 @@ spec: containers: - name: redis - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent command: - redis-server args: - /data/conf/redis.conf securityContext: - null + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault livenessProbe: initialDelaySeconds: 30 periodSeconds: 15 @@ -1256,14 +1298,21 @@ spec: - /bin/sh - /readonly-config/trigger-failover-if-master.sh - name: sentinel - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent command: - redis-sentinel args: - /data/conf/sentinel.conf securityContext: - null + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault livenessProbe: initialDelaySeconds: 30 periodSeconds: 15 @@ -1300,14 +1349,21 @@ spec: {} - name: split-brain-fix - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent command: - sh args: - /readonly-config/fix-split-brain.sh securityContext: - null + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + runAsUser: 1000 + seccompProfile: + type: RuntimeDefault env: - name: SENTINEL_ID_0 value: 3c0d9c0320bb34888c2df5757c718ce6ca992ce6 diff --git a/manifests/ha/base/redis-ha/chart/values.yaml b/manifests/ha/base/redis-ha/chart/values.yaml index db8973b575627..5606daac34bb3 100644 --- a/manifests/ha/base/redis-ha/chart/values.yaml +++ b/manifests/ha/base/redis-ha/chart/values.yaml @@ -11,14 +11,16 @@ redis-ha: IPv6: enabled: false image: - tag: 2.6.2-alpine + tag: 2.6.14-alpine containerSecurityContext: null timeout: server: 6m client: 6m checkInterval: 3s + metrics: + enabled: true image: - tag: 7.0.7-alpine + tag: 7.0.14-alpine containerSecurityContext: null sentinel: bind: "0.0.0.0" diff --git a/manifests/ha/base/redis-ha/kustomization.yaml b/manifests/ha/base/redis-ha/kustomization.yaml index 373a9754527ac..bf0c6c3dff255 100644 --- a/manifests/ha/base/redis-ha/kustomization.yaml +++ b/manifests/ha/base/redis-ha/kustomization.yaml @@ -6,7 +6,7 @@ resources: - argocd-redis-ha-proxy-network-policy.yaml - argocd-redis-ha-server-network-policy.yaml -patchesJson6902: +patches: - target: version: v1 group: "" diff --git a/manifests/ha/base/redis-ha/overlays/deployment-containers-securityContext.yaml b/manifests/ha/base/redis-ha/overlays/deployment-containers-securityContext.yaml index 812e97d8049cf..8ce2b23f876a2 100644 --- a/manifests/ha/base/redis-ha/overlays/deployment-containers-securityContext.yaml +++ b/manifests/ha/base/redis-ha/overlays/deployment-containers-securityContext.yaml @@ -1,6 +1,7 @@ - op: add path: /spec/template/spec/initContainers/0/securityContext value: + readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: @@ -10,6 +11,7 @@ - op: add path: /spec/template/spec/containers/0/securityContext value: + readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: diff --git a/manifests/ha/base/redis-ha/overlays/statefulset-containers-securityContext.yaml b/manifests/ha/base/redis-ha/overlays/statefulset-containers-securityContext.yaml index 386b219575eb7..53b395e14da12 100644 --- a/manifests/ha/base/redis-ha/overlays/statefulset-containers-securityContext.yaml +++ b/manifests/ha/base/redis-ha/overlays/statefulset-containers-securityContext.yaml @@ -1,6 +1,7 @@ - op: add path: /spec/template/spec/initContainers/0/securityContext value: + readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: @@ -10,6 +11,7 @@ - op: add path: /spec/template/spec/containers/0/securityContext value: + readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: @@ -19,6 +21,7 @@ - op: add path: /spec/template/spec/containers/1/securityContext value: + readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: @@ -28,6 +31,7 @@ - op: add path: /spec/template/spec/containers/2/securityContext value: + readOnlyRootFilesystem: true allowPrivilegeEscalation: false capabilities: drop: diff --git a/manifests/ha/install.yaml b/manifests/ha/install.yaml index 62461d59ffa66..9ce3b1cb4b824 100644 --- a/manifests/ha/install.yaml +++ b/manifests/ha/install.yaml @@ -287,8 +287,15 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be + passed to helm template, defined as a map. This takes + precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -303,12 +310,22 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -326,6 +343,10 @@ spec: definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether to + apply common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -334,6 +355,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -549,8 +624,15 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be + passed to helm template, defined as a map. This takes + precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -565,12 +647,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -589,6 +682,10 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -597,6 +694,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -718,7 +869,8 @@ spec: properties: name: description: Name is an alternate way of specifying the target - cluster by its symbolic name + cluster by its symbolic name. This must be set if Server is + not set. type: string namespace: description: Namespace specifies the target namespace for the @@ -726,8 +878,9 @@ spec: namespace-scoped resources that have not set a value for .metadata.namespace type: string server: - description: Server specifies the URL of the target cluster and - must be set to the Kubernetes control plane API + description: Server specifies the URL of the target cluster's + Kubernetes control plane API. This must be set if Name is not + set. type: string type: object ignoreDifferences: @@ -927,8 +1080,15 @@ spec: type: array values: description: Values specifies Helm values to be passed to - helm template, typically defined as a block + helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be passed + to helm template, defined as a map. This takes precedence + over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -943,12 +1103,22 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether to + apply env variables substitution for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -965,6 +1135,10 @@ spec: definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether to apply + common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -973,6 +1147,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize adds + to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas override + specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -1180,8 +1408,15 @@ spec: type: array values: description: Values specifies Helm values to be passed to - helm template, typically defined as a block + helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be passed + to helm template, defined as a map. This takes precedence + over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -1196,12 +1431,22 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -1219,6 +1464,10 @@ spec: definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether to apply + common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -1227,6 +1476,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas override + specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -1319,7 +1622,7 @@ spec: as part of automated sync (default: false)' type: boolean selfHeal: - description: 'SelfHeal specifes whether to revert resources + description: 'SelfHeal specifies whether to revert resources back to their desired state upon modification in the cluster (default: false)' type: boolean @@ -1383,7 +1686,7 @@ spec: conditions items: description: ApplicationCondition contains details about an application - condition, which is usally an error or warning + condition, which is usually an error or warning properties: lastTransitionTime: description: LastTransitionTime is the time the condition was @@ -1402,6 +1705,10 @@ spec: - type type: object type: array + controllerNamespace: + description: ControllerNamespace indicates the namespace in which + the application controller is located + type: string health: description: Health contains information about the application's current health status @@ -1435,6 +1742,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 @@ -1581,8 +1901,15 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be + passed to helm template, defined as a map. This takes + precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -1597,12 +1924,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -1621,6 +1959,10 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -1629,6 +1971,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -1846,8 +2242,16 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. + ValuesObject takes precedence over Values, so use + one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to + be passed to helm template, defined as a map. This + takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -1862,12 +2266,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -1886,6 +2301,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -1894,6 +2314,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -2256,8 +2730,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined as - a block + a block. ValuesObject takes precedence over + Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as a + map. This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -2272,12 +2753,24 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution + for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -2296,6 +2789,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors + or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -2304,14 +2802,68 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string - version: - description: Version controls which version of - Kustomize to use for rendering manifests + namespace: + description: Namespace sets the namespace that + Kustomize adds to all resources type: string - type: object - path: - description: Path is a directory path within the Git - repository, and is only valid for applications sourced + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array + version: + description: Version controls which version of + Kustomize to use for rendering manifests + type: string + type: object + path: + description: Path is a directory path within the Git + repository, and is only valid for applications sourced from Git. type: string plugin: @@ -2537,8 +3089,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined - as a block + as a block. ValuesObject takes precedence + over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as + a map. This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -2555,12 +3114,24 @@ spec: additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution + for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -2579,6 +3150,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies + whether to apply common labels to resource + selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -2587,6 +3163,61 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that + Kustomize adds to all resources + type: string + patches: + description: Patches is a list of Kustomize + patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize + Replicas override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -2720,6 +3351,19 @@ spec: syncResult: description: SyncResult is the result of a Sync operation properties: + managedNamespaceMetadata: + description: ManagedNamespaceMetadata contains the current + sync state of managed namespace metadata + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object resources: description: Resources contains a list of sync result items for each individual resource in a sync operation @@ -2922,8 +3566,16 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. + ValuesObject takes precedence over Values, so use + one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to + be passed to helm template, defined as a map. This + takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -2938,12 +3590,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -2962,6 +3625,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -2970,6 +3638,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -3198,8 +3920,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined as - a block + a block. ValuesObject takes precedence over Values, + so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as a map. + This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -3214,12 +3943,24 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution for + annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -3238,6 +3979,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -3246,6 +3992,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -3428,7 +4228,8 @@ spec: properties: name: description: Name is an alternate way of specifying the - target cluster by its symbolic name + target cluster by its symbolic name. This must be set + if Server is not set. type: string namespace: description: Namespace specifies the target namespace @@ -3437,10 +4238,47 @@ spec: not set a value for .metadata.namespace type: string server: - description: Server specifies the URL of the target cluster - and must be set to the Kubernetes control plane API + description: Server specifies the URL of the target cluster's + Kubernetes control plane API. This must be set if Name + is not set. type: string type: object + ignoreDifferences: + description: IgnoreDifferences is a reference to the application's + ignored differences used for comparison + items: + description: ResourceIgnoreDifferences contains resource + filter and list of json paths which should be ignored + during comparison with live state. + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + description: ManagedFieldsManagers is a list of trusted + managers. Fields mutated by those managers will take + precedence over the desired state defined in the SCM + and won't be displayed in diffs + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array source: description: Source is a reference to the application's source used for comparison @@ -3579,8 +4417,16 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. + ValuesObject takes precedence over Values, so use + one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to + be passed to helm template, defined as a map. This + takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -3595,12 +4441,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -3619,6 +4476,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -3627,6 +4489,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -3855,8 +4771,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined as - a block + a block. ValuesObject takes precedence over Values, + so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as a map. + This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -3871,12 +4794,24 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution for + annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -3895,6 +4830,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -3903,33 +4843,87 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string - version: - description: Version controls which version of Kustomize - to use for rendering manifests + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources type: string - type: object - path: - description: Path is a directory path within the Git - repository, and is only valid for applications sourced - from Git. - type: string - plugin: - description: Plugin holds config management plugin specific - options - properties: - env: - description: Env is a list of environment variable - entries + patches: + description: Patches is a list of Kustomize patches items: - description: EnvEntry represents an entry in the - application's environment properties: - name: - description: Name is the name of the variable, - usually expressed in uppercase + options: + additionalProperties: + type: boolean + type: object + patch: type: string - value: - description: Value is the value of the variable + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array + version: + description: Version controls which version of Kustomize + to use for rendering manifests + type: string + type: object + path: + description: Path is a directory path within the Git + repository, and is only valid for applications sourced + from Git. + type: string + plugin: + description: Plugin holds config management plugin specific + options + properties: + env: + description: Env is a list of environment variable + entries + items: + description: EnvEntry represents an entry in the + application's environment + properties: + name: + description: Name is the name of the variable, + usually expressed in uppercase + type: string + value: + description: Value is the value of the variable type: string required: - name @@ -4043,6 +5037,8 @@ spec: type: object spec: properties: + applyNestedSelectors: + type: boolean generators: items: properties: @@ -4238,6 +5234,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4247,10 +5246,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4259,10 +5264,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4396,6 +5450,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4405,10 +5462,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4417,10 +5480,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4713,6 +5825,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4722,10 +5837,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4734,10 +5855,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4871,6 +6041,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4880,10 +6053,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4892,10 +6071,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5192,6 +6420,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5201,10 +6432,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5213,10 +6450,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5350,6 +6636,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5359,10 +6648,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5371,25 +6666,74 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string - version: + namespace: type: string - type: object - path: - type: string - plugin: - properties: - env: + patches: items: properties: - name: + options: + additionalProperties: + type: boolean + type: object + patch: type: string - value: + path: type: string - required: + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: - name - value type: object @@ -5475,6 +6819,10 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object required: - repoURL - revision @@ -5485,6 +6833,8 @@ spec: items: x-kubernetes-preserve-unknown-fields: true type: array + elementsYaml: + type: string template: properties: metadata: @@ -5645,6 +6995,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5654,10 +7007,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5666,10 +7025,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5803,6 +7211,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5812,10 +7223,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5824,10 +7241,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5928,8 +7394,6 @@ spec: - metadata - spec type: object - required: - - elements type: object matrix: properties: @@ -6128,6 +7592,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6137,10 +7604,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6149,10 +7622,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -6286,6 +7808,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6295,10 +7820,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6307,10 +7838,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -6603,6 +8183,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6612,10 +8195,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6624,10 +8213,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -6761,6 +8399,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6770,10 +8411,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6782,10 +8429,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7082,6 +8778,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7091,10 +8790,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7103,10 +8808,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7240,6 +8994,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7249,10 +9006,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7261,10 +9024,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7365,6 +9177,10 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object required: - repoURL - revision @@ -7375,6 +9191,8 @@ spec: items: x-kubernetes-preserve-unknown-fields: true type: array + elementsYaml: + type: string template: properties: metadata: @@ -7535,6 +9353,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7544,10 +9365,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7556,10 +9383,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7693,6 +9569,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7702,10 +9581,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7714,10 +9599,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7818,153 +9752,49 @@ spec: - metadata - spec type: object - required: - - elements type: object matrix: x-kubernetes-preserve-unknown-fields: true merge: x-kubernetes-preserve-unknown-fields: true - pullRequest: + plugin: properties: - bitbucketServer: + configMapRef: properties: - api: - type: string - basicAuth: - properties: - passwordRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - username: - type: string - required: - - passwordRef - - username - type: object - project: - type: string - repo: + name: type: string required: - - api - - project - - repo + - name type: object - filters: - items: - properties: - branchMatch: - type: string - type: object - type: array - gitea: + input: properties: - api: - type: string - insecure: - type: boolean - owner: - type: string - repo: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName + parameters: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true type: object - required: - - api - - owner - - repo type: object - github: + requeueAfterSeconds: + format: int64 + type: integer + template: properties: - api: - type: string - appSecretName: - type: string - labels: - items: - type: string - type: array - owner: - type: string - repo: - type: string - tokenRef: + metadata: properties: - key: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - owner - - repo - type: object - gitlab: - properties: - api: - type: string - labels: - items: - type: string - type: array - project: - type: string - pullRequestState: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - project - type: object - requeueAfterSeconds: - format: int64 - type: integer - template: - properties: - metadata: - properties: - annotations: - additionalProperties: - type: string - type: object - finalizers: - items: - type: string - type: array - labels: - additionalProperties: - type: string - type: object - name: - type: string - namespace: + namespace: type: string type: object spec: @@ -8106,6 +9936,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8115,10 +9948,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8127,10 +9966,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -8264,6 +10152,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8273,10 +10164,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8285,10 +10182,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -8389,12 +10335,30 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object + required: + - configMapRef type: object - scmProvider: + pullRequest: properties: - azureDevOps: + azuredevops: properties: - accessTokenRef: + api: + type: string + labels: + items: + type: string + type: array + organization: + type: string + project: + type: string + repo: + type: string + tokenRef: properties: key: type: string @@ -8404,46 +10368,58 @@ spec: - key - secretName type: object - allBranches: - type: boolean - api: - type: string - organization: - type: string - teamProject: - type: string required: - - accessTokenRef - organization - - teamProject + - project + - repo type: object bitbucket: properties: - allBranches: - type: boolean - appPasswordRef: + api: + type: string + basicAuth: properties: - key: - type: string - secretName: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: type: string required: - - key - - secretName + - passwordRef + - username + type: object + bearerToken: + properties: + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - tokenRef type: object owner: type: string - user: + repo: type: string required: - - appPasswordRef - owner - - user + - repo type: object bitbucketServer: properties: - allBranches: - type: boolean api: type: string basicAuth: @@ -8466,41 +10442,32 @@ spec: type: object project: type: string + repo: + type: string required: - api - project + - repo type: object - cloneProtocol: - type: string filters: items: properties: branchMatch: type: string - labelMatch: - type: string - pathsDoNotExist: - items: - type: string - type: array - pathsExist: - items: - type: string - type: array - repositoryMatch: + targetBranchMatch: type: string type: object type: array gitea: properties: - allBranches: - type: boolean api: type: string insecure: type: boolean owner: type: string + repo: + type: string tokenRef: properties: key: @@ -8514,16 +10481,21 @@ spec: required: - api - owner + - repo type: object github: properties: - allBranches: - type: boolean api: type: string appSecretName: type: string - organization: + labels: + items: + type: string + type: array + owner: + type: string + repo: type: string tokenRef: properties: @@ -8536,18 +10508,23 @@ spec: - secretName type: object required: - - organization + - owner + - repo type: object gitlab: properties: - allBranches: - type: boolean api: type: string - group: - type: string - includeSubgroups: + insecure: type: boolean + labels: + items: + type: string + type: array + project: + type: string + pullRequestState: + type: string tokenRef: properties: key: @@ -8559,7 +10536,7 @@ spec: - secretName type: object required: - - group + - project type: object requeueAfterSeconds: format: int64 @@ -8724,6 +10701,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8733,10 +10713,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8745,23 +10731,72 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string - version: + namespace: type: string - type: object - path: - type: string - plugin: - properties: - env: + patches: items: properties: - name: - type: string - value: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: type: string required: - name @@ -8882,6 +10917,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8891,10 +10929,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8903,10 +10947,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -9008,511 +11101,203 @@ spec: - spec type: object type: object - selector: + scmProvider: properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - type: string - values: - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - type: object - type: object - type: object - type: array - template: - properties: - metadata: - properties: - annotations: - additionalProperties: - type: string - type: object - finalizers: - items: - type: string - type: array - labels: - additionalProperties: - type: string - type: object - name: - type: string - namespace: - type: string - type: object - spec: - properties: - destination: - properties: - name: - type: string - namespace: - type: string - server: - type: string - type: object - ignoreDifferences: - items: + awsCodeCommit: properties: - group: + allBranches: + type: boolean + region: type: string - jqPathExpressions: - items: - type: string - type: array - jsonPointers: - items: - type: string - type: array - kind: + role: type: string - managedFieldsManagers: + tagFilters: items: - type: string + properties: + key: + type: string + value: + type: string + required: + - key + type: object type: array - name: + type: object + azureDevOps: + properties: + accessTokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + allBranches: + type: boolean + api: type: string - namespace: + organization: + type: string + teamProject: type: string required: - - kind + - accessTokenRef + - organization + - teamProject type: object - type: array - info: - items: + bitbucket: properties: - name: + allBranches: + type: boolean + appPasswordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + owner: type: string - value: + user: type: string required: - - name - - value + - appPasswordRef + - owner + - user type: object - type: array - project: - type: string - revisionHistoryLimit: - format: int64 - type: integer - source: - properties: - chart: - type: string - directory: + bitbucketServer: + properties: + allBranches: + type: boolean + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + project: + type: string + required: + - api + - project + type: object + cloneProtocol: + type: string + filters: + items: properties: - exclude: + branchMatch: type: string - include: + labelMatch: type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean - type: object - helm: - properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: - type: boolean - valueFiles: + pathsDoNotExist: items: type: string type: array - values: - type: string - version: - type: string - type: object - kustomize: - properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: - type: boolean - images: + pathsExist: items: type: string type: array - namePrefix: - type: string - nameSuffix: - type: string - version: - type: string - type: object - path: - type: string - plugin: - properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - name: + repositoryMatch: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array type: object - ref: - type: string - repoURL: - type: string - targetRevision: - type: string - required: - - repoURL - type: object - sources: - items: + type: array + gitea: properties: - chart: + allBranches: + type: boolean + api: type: string - directory: + insecure: + type: boolean + owner: + type: string + tokenRef: properties: - exclude: + key: type: string - include: + secretName: type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean + required: + - key + - secretName type: object - helm: + required: + - api + - owner + type: object + github: + properties: + allBranches: + type: boolean + api: + type: string + appSecretName: + type: string + organization: + type: string + tokenRef: properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: - type: boolean - valueFiles: - items: - type: string - type: array - values: + key: type: string - version: + secretName: type: string + required: + - key + - secretName type: object - kustomize: - properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: - type: boolean - images: - items: - type: string - type: array - namePrefix: - type: string - nameSuffix: - type: string - version: - type: string - type: object - path: + required: + - organization + type: object + gitlab: + properties: + allBranches: + type: boolean + api: type: string - plugin: + group: + type: string + includeSharedProjects: + type: boolean + includeSubgroups: + type: boolean + insecure: + type: boolean + tokenRef: properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - name: + key: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array + secretName: + type: string + required: + - key + - secretName type: object - ref: - type: string - repoURL: - type: string - targetRevision: + topic: type: string required: - - repoURL - type: object - type: array - syncPolicy: - properties: - automated: - properties: - allowEmpty: - type: boolean - prune: - type: boolean - selfHeal: - type: boolean - type: object - managedNamespaceMetadata: - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - retry: - properties: - backoff: - properties: - duration: - type: string - factor: - format: int64 - type: integer - maxDuration: - type: string - type: object - limit: - format: int64 - type: integer - type: object - syncOptions: - items: - type: string - type: array - type: object - required: - - destination - - project - type: object - required: - - metadata - - spec - type: object - required: - - generators - type: object - merge: - properties: - generators: - items: - properties: - clusterDecisionResource: - properties: - configMapRef: - type: string - labelSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - type: string - values: - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - type: object + - group type: object - name: - type: string requeueAfterSeconds: format: int64 type: integer @@ -9676,6 +11461,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -9685,10 +11473,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9697,10 +11491,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -9834,6 +11677,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -9843,10 +11689,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9855,10 +11707,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -9963,34 +11864,2392 @@ spec: additionalProperties: type: string type: object - required: - - configMapRef type: object - clusters: + selector: properties: - selector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - type: string - values: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + type: array + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: items: type: string type: array - required: - - key - - operator + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array type: object - type: array - matchLabels: - additionalProperties: + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: type: string - type: object - type: object + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + required: + - generators + type: object + merge: + properties: + generators: + items: + properties: + clusterDecisionResource: + properties: + configMapRef: + type: string + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + name: + type: string + requeueAfterSeconds: + format: int64 + type: integer + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + required: + - configMapRef + type: object + clusters: + properties: + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + type: object + git: + properties: + directories: + items: + properties: + exclude: + type: boolean + path: + type: string + required: + - path + type: object + type: array + files: + items: + properties: + path: + type: string + required: + - path + type: object + type: array + pathParamPrefix: + type: string + repoURL: + type: string + requeueAfterSeconds: + format: int64 + type: integer + revision: + type: string + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + required: + - repoURL + - revision + type: object + list: + properties: + elements: + items: + x-kubernetes-preserve-unknown-fields: true + type: array + elementsYaml: + type: string template: properties: metadata: @@ -10151,6 +14410,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10160,10 +14422,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10172,10 +14440,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10309,6 +14626,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10318,10 +14638,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10330,10 +14656,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10434,42 +14809,30 @@ spec: - metadata - spec type: object - values: - additionalProperties: - type: string - type: object type: object - git: + matrix: + x-kubernetes-preserve-unknown-fields: true + merge: + x-kubernetes-preserve-unknown-fields: true + plugin: properties: - directories: - items: - properties: - exclude: - type: boolean - path: - type: string - required: - - path - type: object - type: array - files: - items: - properties: - path: - type: string - required: - - path - type: object - type: array - pathParamPrefix: - type: string - repoURL: - type: string + configMapRef: + properties: + name: + type: string + required: + - name + type: object + input: + properties: + parameters: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object requeueAfterSeconds: format: int64 type: integer - revision: - type: string template: properties: metadata: @@ -10630,6 +14993,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10639,10 +15005,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10651,10 +15023,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10788,6 +15209,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10797,10 +15221,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10809,10 +15239,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10906,23 +15385,219 @@ spec: type: array type: object required: - - destination - - project + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + required: + - configMapRef + type: object + pullRequest: + properties: + azuredevops: + properties: + api: + type: string + labels: + items: + type: string + type: array + organization: + type: string + project: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - organization + - project + - repo + type: object + bitbucket: + properties: + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + bearerToken: + properties: + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - tokenRef type: object + owner: + type: string + repo: + type: string required: - - metadata - - spec + - owner + - repo type: object - required: - - repoURL - - revision - type: object - list: - properties: - elements: + bitbucketServer: + properties: + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + project: + type: string + repo: + type: string + required: + - api + - project + - repo + type: object + filters: items: - x-kubernetes-preserve-unknown-fields: true + properties: + branchMatch: + type: string + targetBranchMatch: + type: string + type: object type: array + gitea: + properties: + api: + type: string + insecure: + type: boolean + owner: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - api + - owner + - repo + type: object + github: + properties: + api: + type: string + appSecretName: + type: string + labels: + items: + type: string + type: array + owner: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - owner + - repo + type: object + gitlab: + properties: + api: + type: string + insecure: + type: boolean + labels: + items: + type: string + type: array + project: + type: string + pullRequestState: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - project + type: object + requeueAfterSeconds: + format: int64 + type: integer template: properties: metadata: @@ -11083,6 +15758,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -11092,10 +15770,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11104,10 +15788,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -11241,6 +15974,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -11250,10 +15986,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11262,10 +16004,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -11359,24 +16150,88 @@ spec: type: array type: object required: - - destination - - project + - destination + - project + type: object + required: + - metadata + - spec + type: object + type: object + scmProvider: + properties: + awsCodeCommit: + properties: + allBranches: + type: boolean + region: + type: string + role: + type: string + tagFilters: + items: + properties: + key: + type: string + value: + type: string + required: + - key + type: object + type: array + type: object + azureDevOps: + properties: + accessTokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + allBranches: + type: boolean + api: + type: string + organization: + type: string + teamProject: + type: string + required: + - accessTokenRef + - organization + - teamProject + type: object + bitbucket: + properties: + allBranches: + type: boolean + appPasswordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName type: object + owner: + type: string + user: + type: string required: - - metadata - - spec + - appPasswordRef + - owner + - user type: object - required: - - elements - type: object - matrix: - x-kubernetes-preserve-unknown-fields: true - merge: - x-kubernetes-preserve-unknown-fields: true - pullRequest: - properties: bitbucketServer: properties: + allBranches: + type: boolean api: type: string basicAuth: @@ -11399,30 +16254,41 @@ spec: type: object project: type: string - repo: - type: string required: - api - project - - repo type: object + cloneProtocol: + type: string filters: items: properties: branchMatch: type: string + labelMatch: + type: string + pathsDoNotExist: + items: + type: string + type: array + pathsExist: + items: + type: string + type: array + repositoryMatch: + type: string type: object type: array gitea: properties: + allBranches: + type: boolean api: type: string insecure: type: boolean owner: type: string - repo: - type: string tokenRef: properties: key: @@ -11436,21 +16302,16 @@ spec: required: - api - owner - - repo type: object github: properties: + allBranches: + type: boolean api: type: string appSecretName: type: string - labels: - items: - type: string - type: array - owner: - type: string - repo: + organization: type: string tokenRef: properties: @@ -11463,21 +16324,22 @@ spec: - secretName type: object required: - - owner - - repo + - organization type: object gitlab: properties: + allBranches: + type: boolean api: type: string - labels: - items: - type: string - type: array - project: - type: string - pullRequestState: + group: type: string + includeSharedProjects: + type: boolean + includeSubgroups: + type: boolean + insecure: + type: boolean tokenRef: properties: key: @@ -11488,8 +16350,10 @@ spec: - key - secretName type: object + topic: + type: string required: - - project + - group type: object requeueAfterSeconds: format: int64 @@ -11654,6 +16518,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -11663,10 +16530,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11675,10 +16548,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -11812,6 +16734,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -11821,10 +16746,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11833,10 +16764,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -11937,654 +16917,622 @@ spec: - metadata - spec type: object - type: object - scmProvider: - properties: - azureDevOps: - properties: - accessTokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - allBranches: - type: boolean - api: - type: string - organization: - type: string - teamProject: - type: string - required: - - accessTokenRef - - organization - - teamProject - type: object - bitbucket: - properties: - allBranches: - type: boolean - appPasswordRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - owner: - type: string - user: - type: string - required: - - appPasswordRef - - owner - - user - type: object - bitbucketServer: - properties: - allBranches: - type: boolean - api: - type: string - basicAuth: - properties: - passwordRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - username: - type: string - required: - - passwordRef - - username - type: object - project: - type: string - required: - - api - - project + values: + additionalProperties: + type: string type: object - cloneProtocol: - type: string - filters: + type: object + selector: + properties: + matchExpressions: items: properties: - branchMatch: + key: type: string - labelMatch: + operator: type: string - pathsDoNotExist: - items: - type: string - type: array - pathsExist: + values: items: type: string type: array - repositoryMatch: - type: string + required: + - key + - operator type: object type: array - gitea: - properties: - allBranches: - type: boolean - api: - type: string - insecure: - type: boolean - owner: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - api - - owner + matchLabels: + additionalProperties: + type: string type: object - github: + type: object + type: object + type: array + mergeKeys: + items: + type: string + type: array + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: properties: - allBranches: - type: boolean - api: + group: type: string - appSecretName: + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: type: string - organization: + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object required: - - organization + - kind type: object - gitlab: + type: array + info: + items: properties: - allBranches: - type: boolean - api: + name: type: string - group: + value: type: string - includeSubgroups: - type: boolean - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object required: - - group + - name + - value type: object - requeueAfterSeconds: - format: int64 - type: integer - template: - properties: - metadata: - properties: - annotations: - additionalProperties: - type: string + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string type: object - finalizers: - items: - type: string - type: array - labels: - additionalProperties: - type: string + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string type: object - name: + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: type: string - namespace: + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: type: string - type: object - spec: - properties: - destination: - properties: - name: - type: string - namespace: - type: string - server: - type: string - type: object - ignoreDifferences: - items: - properties: - group: - type: string - jqPathExpressions: - items: - type: string - type: array - jsonPointers: - items: - type: string - type: array - kind: - type: string - managedFieldsManagers: - items: - type: string - type: array - name: - type: string - namespace: - type: string - required: - - kind - type: object - type: array - info: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - project: + type: object + components: + items: type: string - revisionHistoryLimit: - format: int64 - type: integer - source: + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: properties: - chart: + options: + additionalProperties: + type: boolean + type: object + patch: type: string - directory: + path: + type: string + target: properties: - exclude: - type: string - include: + annotationSelector: type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean - type: object - helm: - properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: + group: type: string - skipCrds: - type: boolean - valueFiles: - items: - type: string - type: array - values: + kind: type: string - version: + labelSelector: type: string - type: object - kustomize: - properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: - type: boolean - images: - items: - type: string - type: array - namePrefix: + name: type: string - nameSuffix: + namespace: type: string version: type: string type: object - path: + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: type: string - plugin: - properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - name: - type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string type: object - ref: - type: string - repoURL: + name: type: string - targetRevision: + string: type: string - required: - - repoURL type: object - sources: - items: - properties: - chart: - type: string - directory: - properties: - exclude: - type: string - include: - type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean - type: object - helm: + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: + code: type: boolean - valueFiles: - items: - type: string - type: array - values: + name: type: string - version: + value: type: string + required: + - name + - value type: object - kustomize: + type: array + libs: + items: + type: string + type: array + tlas: + items: properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: + code: type: boolean - images: - items: - type: string - type: array - namePrefix: - type: string - nameSuffix: + name: type: string - version: + value: type: string + required: + - name + - value type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string path: type: string - plugin: - properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string name: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array + namespace: + type: string + version: + type: string type: object - ref: + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: type: string - repoURL: + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: type: string - targetRevision: + value: type: string required: - - repoURL + - name + - value type: object type: array - syncPolicy: - properties: - automated: - properties: - allowEmpty: - type: boolean - prune: - type: boolean - selfHeal: - type: boolean - type: object - managedNamespaceMetadata: - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - retry: - properties: - backoff: - properties: - duration: - type: string - factor: - format: int64 - type: integer - maxDuration: - type: string - type: object - limit: - format: int64 - type: integer - type: object - syncOptions: - items: + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: type: string - type: array - type: object - required: - - destination - - project + string: + type: string + type: object + type: array type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string required: - - metadata - - spec + - repoURL type: object - type: object - selector: - properties: - matchExpressions: - items: + type: array + syncPolicy: + properties: + automated: properties: - key: - type: string - operator: - type: string - values: - items: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: type: string - type: array - required: - - key - - operator + type: object + labels: + additionalProperties: + type: string + type: object type: object - type: array - matchLabels: - additionalProperties: - type: string - type: object - type: object - type: object - type: array - mergeKeys: - items: - type: string - type: array + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + required: + - generators + - mergeKeys + type: object + plugin: + properties: + configMapRef: + properties: + name: + type: string + required: + - name + type: object + input: + properties: + parameters: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + requeueAfterSeconds: + format: int64 + type: integer template: properties: metadata: @@ -12745,6 +17693,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -12754,10 +17705,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12766,10 +17723,59 @@ spec: items: type: string type: array - namePrefix: - type: string - nameSuffix: - type: string + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -12903,6 +17909,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -12912,10 +17921,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12924,10 +17939,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -13028,12 +18092,89 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object required: - - generators - - mergeKeys + - configMapRef type: object pullRequest: properties: + azuredevops: + properties: + api: + type: string + labels: + items: + type: string + type: array + organization: + type: string + project: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - organization + - project + - repo + type: object + bitbucket: + properties: + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + bearerToken: + properties: + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - tokenRef + type: object + owner: + type: string + repo: + type: string + required: + - owner + - repo + type: object bitbucketServer: properties: api: @@ -13070,6 +18211,8 @@ spec: properties: branchMatch: type: string + targetBranchMatch: + type: string type: object type: array gitea: @@ -13129,6 +18272,8 @@ spec: properties: api: type: string + insecure: + type: boolean labels: items: type: string @@ -13313,6 +18458,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -13322,10 +18470,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13334,10 +18488,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -13471,6 +18674,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -13480,10 +18686,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13492,10 +18704,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -13599,6 +18860,26 @@ spec: type: object scmProvider: properties: + awsCodeCommit: + properties: + allBranches: + type: boolean + region: + type: string + role: + type: string + tagFilters: + items: + properties: + key: + type: string + value: + type: string + required: + - key + type: object + type: array + type: object azureDevOps: properties: accessTokenRef: @@ -13753,8 +19034,12 @@ spec: type: string group: type: string + includeSharedProjects: + type: boolean includeSubgroups: type: boolean + insecure: + type: boolean tokenRef: properties: key: @@ -13765,6 +19050,8 @@ spec: - key - secretName type: object + topic: + type: string required: - group type: object @@ -13931,6 +19218,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -13940,10 +19230,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13952,10 +19248,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -14089,6 +19434,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -14098,10 +19446,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14110,10 +19464,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -14214,6 +19617,10 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object type: object selector: properties: @@ -14242,6 +19649,36 @@ spec: type: array goTemplate: type: boolean + goTemplateOptions: + items: + type: string + type: array + ignoreApplicationDifferences: + items: + properties: + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + name: + type: string + type: object + type: array + preservedFields: + properties: + annotations: + items: + type: string + type: array + labels: + items: + type: string + type: array + type: object strategy: properties: rollingSync: @@ -14275,6 +19712,13 @@ spec: type: object syncPolicy: properties: + applicationsSync: + enum: + - create-only + - create-update + - create-delete + - sync + type: string preserveResourcesOnDeletion: type: boolean type: object @@ -14438,6 +19882,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -14447,10 +19894,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14459,10 +19912,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -14596,6 +20098,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -14605,10 +20110,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14617,10 +20128,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -14721,6 +20281,8 @@ spec: - metadata - spec type: object + templatePatch: + type: string required: - generators - template @@ -14739,10 +20301,13 @@ spec: type: string status: type: string + step: + type: string required: - application - message - status + - step type: object type: array conditions: @@ -14866,7 +20431,8 @@ spec: properties: name: description: Name is an alternate way of specifying the target - cluster by its symbolic name + cluster by its symbolic name. This must be set if Server is + not set. type: string namespace: description: Namespace specifies the target namespace for the @@ -14874,8 +20440,9 @@ spec: namespace-scoped resources that have not set a value for .metadata.namespace type: string server: - description: Server specifies the URL of the target cluster - and must be set to the Kubernetes control plane API + description: Server specifies the URL of the target cluster's + Kubernetes control plane API. This must be set if Name is + not set. type: string type: object type: array @@ -15112,9 +20679,9 @@ apiVersion: v1 kind: ServiceAccount metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller --- apiVersion: v1 @@ -15209,14 +20776,22 @@ rules: verbs: - create - list +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller rules: - apiGroups: @@ -15298,6 +20873,10 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller rules: - apiGroups: @@ -15434,6 +21013,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 @@ -15465,11 +21133,24 @@ rules: - apiGroups: - argoproj.io resources: - - applications + - applications + - applicationsets + verbs: + - get + - list + - watch +- apiGroups: + - batch + resources: + - jobs + verbs: + - create +- apiGroups: + - argoproj.io + resources: + - workflows verbs: - - get - - list - - watch + - create --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding @@ -15491,9 +21172,9 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller roleRef: apiGroup: rbac.authorization.k8s.io @@ -15522,6 +21203,10 @@ subjects: apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller roleRef: apiGroup: rbac.authorization.k8s.io @@ -15598,6 +21283,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 @@ -15622,6 +21324,8 @@ metadata: name: argocd-cm --- apiVersion: v1 +data: + redis.server: argocd-redis-ha-haproxy:6379 kind: ConfigMap metadata: labels: @@ -15640,6 +21344,10 @@ metadata: apiVersion: v1 kind: ConfigMap metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-cm --- apiVersion: v1 @@ -15971,7 +21679,9 @@ data: check inter 3s fall 1 rise 1\n use-server R1 if { srv_is_up(R1) } { nbsrv(check_if_redis_is_master_1) ge 2 }\n server R1 argocd-redis-ha-announce-1:6379 check inter 3s fall 1 rise 1\n use-server R2 if { srv_is_up(R2) } { nbsrv(check_if_redis_is_master_2) ge - 2 }\n server R2 argocd-redis-ha-announce-2:6379 check inter 3s fall 1 rise 1\n" + 2 }\n server R2 argocd-redis-ha-announce-2:6379 check inter 3s fall 1 rise 1\nfrontend + stats\n mode http\n bind :9101 \n http-request use-service prometheus-exporter + if { path /metrics }\n stats enable\n stats uri /stats\n stats refresh 10s\n" haproxy_init.sh: | HAPROXY_CONF=/data/haproxy.cfg cp /readonly/haproxy.cfg "$HAPROXY_CONF" @@ -16373,16 +22083,22 @@ metadata: --- apiVersion: v1 data: - ssh_known_hosts: |- - bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== - github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== + ssh_known_hosts: | + # This file was automatically generated by hack/update-ssh-known-hosts.sh. DO NOT EDIT + [ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + [ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + [ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= + bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= + bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO + bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M= + github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H - github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= - github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl kind: ConfigMap metadata: labels: @@ -16401,6 +22117,10 @@ metadata: apiVersion: v1 kind: Secret metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-secret type: Opaque --- @@ -16417,9 +22137,9 @@ apiVersion: v1 kind: Service metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller spec: ports: @@ -16444,7 +22164,8 @@ metadata: name: argocd-dex-server spec: ports: - - name: http + - appProtocol: TCP + name: http port: 5556 protocol: TCP targetPort: 5556 @@ -16480,7 +22201,9 @@ apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: notifications-controller app.kubernetes.io/name: argocd-notifications-controller-metrics + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller-metrics spec: ports: @@ -16606,6 +22329,10 @@ spec: port: 6379 protocol: TCP targetPort: redis + - name: http-exporter-port + port: 9101 + protocol: TCP + targetPort: metrics-port selector: app.kubernetes.io/name: argocd-redis-ha-haproxy type: ClusterIP @@ -16673,9 +22400,9 @@ apiVersion: apps/v1 kind: Deployment metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller spec: selector: @@ -16687,10 +22414,21 @@ spec: app.kubernetes.io/name: argocd-applicationset-controller spec: containers: - - command: - - entrypoint.sh - - argocd-applicationset-controller + - args: + - /usr/local/bin/argocd-applicationset-controller env: + - name: ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_ANNOTATIONS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.global.preserved.annotations + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_LABELS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.global.preserved.labels + name: argocd-cmd-params-cm + optional: true - name: NAMESPACE valueFrom: fieldRef: @@ -16701,12 +22439,6 @@ spec: key: applicationsetcontroller.enable.leader.election name: argocd-cmd-params-cm optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACE - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.namespace - name: argocd-cmd-params-cm - optional: true - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER valueFrom: configMapKeyRef: @@ -16719,6 +22451,12 @@ spec: key: applicationsetcontroller.policy name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.policy.override + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG valueFrom: configMapKeyRef: @@ -16749,10 +22487,64 @@ spec: key: applicationsetcontroller.enable.git.submodule name: argocd-cmd-params-cm optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS valueFrom: configMapKeyRef: - key: applicationsetcontroller.enable.progressive.rollouts + key: applicationsetcontroller.enable.progressive.syncs + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.new.git.file.globbing + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.strict.tls + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.timeout.seconds + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_CONCURRENT_RECONCILIATIONS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.concurrent.reconciliations.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.namespaces + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.scm.root.ca.path + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.allowed.scm.providers + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.scm.providers name: argocd-cmd-params-cm optional: true image: quay.io/argoproj/argocd:latest @@ -16783,6 +22575,8 @@ spec: name: gpg-keyring - mountPath: /tmp name: tmp + - mountPath: /app/config/reposerver/tls + name: argocd-repo-server-tls serviceAccountName: argocd-applicationset-controller volumes: - configMap: @@ -16798,6 +22592,17 @@ spec: name: gpg-keyring - emptyDir: {} name: tmp + - name: argocd-repo-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-repo-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -16836,7 +22641,7 @@ spec: key: dexserver.disable.tls name: argocd-cmd-params-cm optional: true - image: ghcr.io/dexidp/dex:v2.35.3 + image: ghcr.io/dexidp/dex:v2.38.0 imagePullPolicy: Always name: dex ports: @@ -16861,7 +22666,7 @@ spec: name: argocd-dex-server-tls initContainers: - command: - - cp + - /bin/cp - -n - /usr/local/bin/argocd - /shared/argocd-dex @@ -16903,6 +22708,10 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller spec: selector: @@ -16916,8 +22725,33 @@ spec: app.kubernetes.io/name: argocd-notifications-controller spec: containers: - - command: - - argocd-notifications + - args: + - /usr/local/bin/argocd-notifications + env: + - name: ARGOCD_NOTIFICATIONS_CONTROLLER_LOGFORMAT + valueFrom: + configMapKeyRef: + key: notificationscontroller.log.format + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_NOTIFICATIONS_CONTROLLER_LOGLEVEL + valueFrom: + configMapKeyRef: + key: notificationscontroller.log.level + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_NAMESPACES + valueFrom: + configMapKeyRef: + 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: @@ -16976,7 +22810,10 @@ spec: template: metadata: annotations: - checksum/config: 718bbb277da8610063a7c0fd810984577c2e8ab215815a71211dfa6e20f67321 + checksum/config: 492a6adabb741e0cee39be9aa5155c41a4456629f862d0006a2d892dbecfbcae + prometheus.io/path: /metrics + prometheus.io/port: "9101" + prometheus.io/scrape: "true" labels: app.kubernetes.io/name: argocd-redis-ha-haproxy name: argocd-redis-ha-haproxy @@ -16989,7 +22826,7 @@ spec: app.kubernetes.io/name: argocd-redis-ha-haproxy topologyKey: kubernetes.io/hostname containers: - - image: haproxy:2.6.2-alpine + - image: haproxy:2.6.14-alpine imagePullPolicy: IfNotPresent lifecycle: {} livenessProbe: @@ -17002,6 +22839,8 @@ spec: ports: - containerPort: 6379 name: redis + - containerPort: 9101 + name: metrics-port readinessProbe: httpGet: path: /healthz @@ -17013,6 +22852,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault volumeMounts: @@ -17025,7 +22865,7 @@ spec: - /readonly/haproxy_init.sh command: - sh - image: haproxy:2.6.2-alpine + image: haproxy:2.6.14-alpine imagePullPolicy: IfNotPresent name: config-init securityContext: @@ -17033,6 +22873,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault volumeMounts: @@ -17080,7 +22921,7 @@ spec: labelSelector: matchLabels: app.kubernetes.io/name: argocd-repo-server - topologyKey: failure-domain.beta.kubernetes.io/zone + topologyKey: topology.kubernetes.io/zone weight: 100 requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: @@ -17089,11 +22930,8 @@ spec: topologyKey: kubernetes.io/hostname automountServiceAccountToken: false containers: - - command: - - entrypoint.sh - - argocd-repo-server - - --redis - - argocd-redis-ha-haproxy:6379 + - args: + - /usr/local/bin/argocd-repo-server env: - name: ARGOCD_RECONCILIATION_TIMEOUT valueFrom: @@ -17119,6 +22957,18 @@ spec: key: reposerver.parallelism.limit name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: reposerver.listen.address + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_LISTEN_METRICS_ADDRESS + valueFrom: + configMapKeyRef: + key: reposerver.metrics.listen.address + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_REPO_SERVER_DISABLE_TLS valueFrom: configMapKeyRef: @@ -17179,6 +23029,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: @@ -17209,12 +23071,42 @@ spec: key: reposerver.streamed.manifest.max.extracted.size name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE + valueFrom: + configMapKeyRef: + key: reposerver.helm.manifest.max.extracted.size + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE + valueFrom: + configMapKeyRef: + key: reposerver.disable.helm.manifest.max.extracted.size + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REVISION_CACHE_LOCK_TIMEOUT + valueFrom: + configMapKeyRef: + key: reposerver.revision.cache.lock.timeout + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_GIT_MODULES_ENABLED valueFrom: configMapKeyRef: 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 @@ -17269,7 +23161,7 @@ spec: name: plugins initContainers: - command: - - cp + - /bin/cp - -n - /usr/local/bin/argocd - /var/run/argocd/argocd-cmp-server @@ -17345,7 +23237,7 @@ spec: labelSelector: matchLabels: app.kubernetes.io/name: argocd-server - topologyKey: failure-domain.beta.kubernetes.io/zone + topologyKey: topology.kubernetes.io/zone weight: 100 requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: @@ -17353,10 +23245,8 @@ spec: app.kubernetes.io/name: argocd-server topologyKey: kubernetes.io/hostname containers: - - command: - - argocd-server - - --redis - - argocd-redis-ha-haproxy:6379 + - args: + - /usr/local/bin/argocd-server env: - name: ARGOCD_API_SERVER_REPLICAS value: "2" @@ -17534,12 +23424,36 @@ spec: key: server.http.cookie.maxnumber name: argocd-cmd-params-cm optional: true + - name: ARGOCD_SERVER_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: server.listen.address + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_SERVER_METRICS_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: server.metrics.listen.address + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_SERVER_OTLP_ADDRESS valueFrom: configMapKeyRef: 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: @@ -17552,6 +23466,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: @@ -17661,10 +23593,8 @@ spec: topologyKey: kubernetes.io/hostname weight: 5 containers: - - command: - - argocd-application-controller - - --redis - - argocd-redis-ha-haproxy:6379 + - args: + - /usr/local/bin/argocd-application-controller env: - name: ARGOCD_CONTROLLER_REPLICAS value: "1" @@ -17680,6 +23610,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: @@ -17782,12 +23724,54 @@ 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: key: application.namespaces name: argocd-cmd-params-cm optional: true + - name: ARGOCD_CONTROLLER_SHARDING_ALGORITHM + valueFrom: + configMapKeyRef: + key: controller.sharding.algorithm + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_KUBECTL_PARALLELISM_LIMIT + valueFrom: + configMapKeyRef: + 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 @@ -17865,7 +23849,7 @@ spec: - /data/conf/redis.conf command: - redis-server - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -17904,6 +23888,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault volumeMounts: @@ -17918,7 +23903,7 @@ spec: - /data/conf/sentinel.conf command: - redis-sentinel - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent lifecycle: {} livenessProbe: @@ -17952,6 +23937,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault volumeMounts: @@ -17970,7 +23956,7 @@ spec: value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4 - name: SENTINEL_ID_2 value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent name: split-brain-fix resources: {} @@ -17979,6 +23965,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault volumeMounts: @@ -17999,7 +23986,7 @@ spec: value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4 - name: SENTINEL_ID_2 value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent name: config-init securityContext: @@ -18007,6 +23994,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault volumeMounts: @@ -18098,6 +24086,10 @@ spec: apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller-network-policy spec: ingress: @@ -18211,6 +24203,9 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-applicationset-controller ports: - port: 8081 protocol: TCP diff --git a/manifests/ha/namespace-install.yaml b/manifests/ha/namespace-install.yaml index 0f56433f0b492..73473875be715 100644 --- a/manifests/ha/namespace-install.yaml +++ b/manifests/ha/namespace-install.yaml @@ -12,9 +12,9 @@ apiVersion: v1 kind: ServiceAccount metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller --- apiVersion: v1 @@ -109,14 +109,22 @@ rules: verbs: - create - list +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller rules: - apiGroups: @@ -198,6 +206,10 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller rules: - apiGroups: @@ -332,9 +344,9 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller roleRef: apiGroup: rbac.authorization.k8s.io @@ -363,6 +375,10 @@ subjects: apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller roleRef: apiGroup: rbac.authorization.k8s.io @@ -429,6 +445,8 @@ metadata: name: argocd-cm --- apiVersion: v1 +data: + redis.server: argocd-redis-ha-haproxy:6379 kind: ConfigMap metadata: labels: @@ -447,6 +465,10 @@ metadata: apiVersion: v1 kind: ConfigMap metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-cm --- apiVersion: v1 @@ -778,7 +800,9 @@ data: check inter 3s fall 1 rise 1\n use-server R1 if { srv_is_up(R1) } { nbsrv(check_if_redis_is_master_1) ge 2 }\n server R1 argocd-redis-ha-announce-1:6379 check inter 3s fall 1 rise 1\n use-server R2 if { srv_is_up(R2) } { nbsrv(check_if_redis_is_master_2) ge - 2 }\n server R2 argocd-redis-ha-announce-2:6379 check inter 3s fall 1 rise 1\n" + 2 }\n server R2 argocd-redis-ha-announce-2:6379 check inter 3s fall 1 rise 1\nfrontend + stats\n mode http\n bind :9101 \n http-request use-service prometheus-exporter + if { path /metrics }\n stats enable\n stats uri /stats\n stats refresh 10s\n" haproxy_init.sh: | HAPROXY_CONF=/data/haproxy.cfg cp /readonly/haproxy.cfg "$HAPROXY_CONF" @@ -1180,16 +1204,22 @@ metadata: --- apiVersion: v1 data: - ssh_known_hosts: |- - bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== - github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== + ssh_known_hosts: | + # This file was automatically generated by hack/update-ssh-known-hosts.sh. DO NOT EDIT + [ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + [ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + [ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= + bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= + bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO + bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M= + github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H - github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= - github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl kind: ConfigMap metadata: labels: @@ -1208,6 +1238,10 @@ metadata: apiVersion: v1 kind: Secret metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-secret type: Opaque --- @@ -1224,9 +1258,9 @@ apiVersion: v1 kind: Service metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller spec: ports: @@ -1251,7 +1285,8 @@ metadata: name: argocd-dex-server spec: ports: - - name: http + - appProtocol: TCP + name: http port: 5556 protocol: TCP targetPort: 5556 @@ -1287,7 +1322,9 @@ apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: notifications-controller app.kubernetes.io/name: argocd-notifications-controller-metrics + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller-metrics spec: ports: @@ -1413,6 +1450,10 @@ spec: port: 6379 protocol: TCP targetPort: redis + - name: http-exporter-port + port: 9101 + protocol: TCP + targetPort: metrics-port selector: app.kubernetes.io/name: argocd-redis-ha-haproxy type: ClusterIP @@ -1480,9 +1521,9 @@ apiVersion: apps/v1 kind: Deployment metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller spec: selector: @@ -1494,10 +1535,21 @@ spec: app.kubernetes.io/name: argocd-applicationset-controller spec: containers: - - command: - - entrypoint.sh - - argocd-applicationset-controller + - args: + - /usr/local/bin/argocd-applicationset-controller env: + - name: ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_ANNOTATIONS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.global.preserved.annotations + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_LABELS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.global.preserved.labels + name: argocd-cmd-params-cm + optional: true - name: NAMESPACE valueFrom: fieldRef: @@ -1508,12 +1560,6 @@ spec: key: applicationsetcontroller.enable.leader.election name: argocd-cmd-params-cm optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACE - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.namespace - name: argocd-cmd-params-cm - optional: true - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER valueFrom: configMapKeyRef: @@ -1526,6 +1572,12 @@ spec: key: applicationsetcontroller.policy name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.policy.override + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG valueFrom: configMapKeyRef: @@ -1556,10 +1608,64 @@ spec: key: applicationsetcontroller.enable.git.submodule name: argocd-cmd-params-cm optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.progressive.syncs + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.new.git.file.globbing + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.strict.tls + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.timeout.seconds + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_CONCURRENT_RECONCILIATIONS valueFrom: configMapKeyRef: - key: applicationsetcontroller.enable.progressive.rollouts + key: applicationsetcontroller.concurrent.reconciliations.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.namespaces + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.scm.root.ca.path + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.allowed.scm.providers + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.scm.providers name: argocd-cmd-params-cm optional: true image: quay.io/argoproj/argocd:latest @@ -1590,6 +1696,8 @@ spec: name: gpg-keyring - mountPath: /tmp name: tmp + - mountPath: /app/config/reposerver/tls + name: argocd-repo-server-tls serviceAccountName: argocd-applicationset-controller volumes: - configMap: @@ -1605,6 +1713,17 @@ spec: name: gpg-keyring - emptyDir: {} name: tmp + - name: argocd-repo-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-repo-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -1643,7 +1762,7 @@ spec: key: dexserver.disable.tls name: argocd-cmd-params-cm optional: true - image: ghcr.io/dexidp/dex:v2.35.3 + image: ghcr.io/dexidp/dex:v2.38.0 imagePullPolicy: Always name: dex ports: @@ -1668,7 +1787,7 @@ spec: name: argocd-dex-server-tls initContainers: - command: - - cp + - /bin/cp - -n - /usr/local/bin/argocd - /shared/argocd-dex @@ -1710,6 +1829,10 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller spec: selector: @@ -1723,8 +1846,33 @@ spec: app.kubernetes.io/name: argocd-notifications-controller spec: containers: - - command: - - argocd-notifications + - args: + - /usr/local/bin/argocd-notifications + env: + - name: ARGOCD_NOTIFICATIONS_CONTROLLER_LOGFORMAT + valueFrom: + configMapKeyRef: + key: notificationscontroller.log.format + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_NOTIFICATIONS_CONTROLLER_LOGLEVEL + valueFrom: + configMapKeyRef: + key: notificationscontroller.log.level + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_NAMESPACES + valueFrom: + configMapKeyRef: + 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: @@ -1783,7 +1931,10 @@ spec: template: metadata: annotations: - checksum/config: 718bbb277da8610063a7c0fd810984577c2e8ab215815a71211dfa6e20f67321 + checksum/config: 492a6adabb741e0cee39be9aa5155c41a4456629f862d0006a2d892dbecfbcae + prometheus.io/path: /metrics + prometheus.io/port: "9101" + prometheus.io/scrape: "true" labels: app.kubernetes.io/name: argocd-redis-ha-haproxy name: argocd-redis-ha-haproxy @@ -1796,7 +1947,7 @@ spec: app.kubernetes.io/name: argocd-redis-ha-haproxy topologyKey: kubernetes.io/hostname containers: - - image: haproxy:2.6.2-alpine + - image: haproxy:2.6.14-alpine imagePullPolicy: IfNotPresent lifecycle: {} livenessProbe: @@ -1809,6 +1960,8 @@ spec: ports: - containerPort: 6379 name: redis + - containerPort: 9101 + name: metrics-port readinessProbe: httpGet: path: /healthz @@ -1820,6 +1973,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault volumeMounts: @@ -1832,7 +1986,7 @@ spec: - /readonly/haproxy_init.sh command: - sh - image: haproxy:2.6.2-alpine + image: haproxy:2.6.14-alpine imagePullPolicy: IfNotPresent name: config-init securityContext: @@ -1840,6 +1994,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault volumeMounts: @@ -1887,7 +2042,7 @@ spec: labelSelector: matchLabels: app.kubernetes.io/name: argocd-repo-server - topologyKey: failure-domain.beta.kubernetes.io/zone + topologyKey: topology.kubernetes.io/zone weight: 100 requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: @@ -1896,11 +2051,8 @@ spec: topologyKey: kubernetes.io/hostname automountServiceAccountToken: false containers: - - command: - - entrypoint.sh - - argocd-repo-server - - --redis - - argocd-redis-ha-haproxy:6379 + - args: + - /usr/local/bin/argocd-repo-server env: - name: ARGOCD_RECONCILIATION_TIMEOUT valueFrom: @@ -1926,6 +2078,18 @@ spec: key: reposerver.parallelism.limit name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: reposerver.listen.address + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_LISTEN_METRICS_ADDRESS + valueFrom: + configMapKeyRef: + key: reposerver.metrics.listen.address + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_REPO_SERVER_DISABLE_TLS valueFrom: configMapKeyRef: @@ -1986,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: @@ -2016,12 +2192,42 @@ spec: key: reposerver.streamed.manifest.max.extracted.size name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE + valueFrom: + configMapKeyRef: + key: reposerver.helm.manifest.max.extracted.size + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE + valueFrom: + configMapKeyRef: + key: reposerver.disable.helm.manifest.max.extracted.size + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REVISION_CACHE_LOCK_TIMEOUT + valueFrom: + configMapKeyRef: + key: reposerver.revision.cache.lock.timeout + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_GIT_MODULES_ENABLED valueFrom: configMapKeyRef: 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 @@ -2076,7 +2282,7 @@ spec: name: plugins initContainers: - command: - - cp + - /bin/cp - -n - /usr/local/bin/argocd - /var/run/argocd/argocd-cmp-server @@ -2152,7 +2358,7 @@ spec: labelSelector: matchLabels: app.kubernetes.io/name: argocd-server - topologyKey: failure-domain.beta.kubernetes.io/zone + topologyKey: topology.kubernetes.io/zone weight: 100 requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: @@ -2160,10 +2366,8 @@ spec: app.kubernetes.io/name: argocd-server topologyKey: kubernetes.io/hostname containers: - - command: - - argocd-server - - --redis - - argocd-redis-ha-haproxy:6379 + - args: + - /usr/local/bin/argocd-server env: - name: ARGOCD_API_SERVER_REPLICAS value: "2" @@ -2341,12 +2545,36 @@ spec: key: server.http.cookie.maxnumber name: argocd-cmd-params-cm optional: true + - name: ARGOCD_SERVER_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: server.listen.address + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_SERVER_METRICS_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: server.metrics.listen.address + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_SERVER_OTLP_ADDRESS valueFrom: configMapKeyRef: 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: @@ -2359,6 +2587,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: @@ -2468,10 +2714,8 @@ spec: topologyKey: kubernetes.io/hostname weight: 5 containers: - - command: - - argocd-application-controller - - --redis - - argocd-redis-ha-haproxy:6379 + - args: + - /usr/local/bin/argocd-application-controller env: - name: ARGOCD_CONTROLLER_REPLICAS value: "1" @@ -2487,6 +2731,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: @@ -2589,12 +2845,54 @@ 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: key: application.namespaces name: argocd-cmd-params-cm optional: true + - name: ARGOCD_CONTROLLER_SHARDING_ALGORITHM + valueFrom: + configMapKeyRef: + key: controller.sharding.algorithm + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_KUBECTL_PARALLELISM_LIMIT + valueFrom: + configMapKeyRef: + 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 @@ -2672,7 +2970,7 @@ spec: - /data/conf/redis.conf command: - redis-server - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -2711,6 +3009,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault volumeMounts: @@ -2725,7 +3024,7 @@ spec: - /data/conf/sentinel.conf command: - redis-sentinel - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent lifecycle: {} livenessProbe: @@ -2759,6 +3058,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault volumeMounts: @@ -2777,7 +3077,7 @@ spec: value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4 - name: SENTINEL_ID_2 value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent name: split-brain-fix resources: {} @@ -2786,6 +3086,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault volumeMounts: @@ -2806,7 +3107,7 @@ spec: value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4 - name: SENTINEL_ID_2 value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent name: config-init securityContext: @@ -2814,6 +3115,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true seccompProfile: type: RuntimeDefault volumeMounts: @@ -2905,6 +3207,10 @@ spec: apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller-network-policy spec: ingress: @@ -3018,6 +3324,9 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-applicationset-controller ports: - port: 8081 protocol: TCP diff --git a/manifests/install.yaml b/manifests/install.yaml index ce867269fafaa..282e6c9f66e7d 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -287,8 +287,15 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be + passed to helm template, defined as a map. This takes + precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -303,12 +310,22 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -326,6 +343,10 @@ spec: definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether to + apply common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -334,6 +355,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -549,8 +624,15 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be + passed to helm template, defined as a map. This takes + precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -565,12 +647,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -589,6 +682,10 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -597,6 +694,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -718,7 +869,8 @@ spec: properties: name: description: Name is an alternate way of specifying the target - cluster by its symbolic name + cluster by its symbolic name. This must be set if Server is + not set. type: string namespace: description: Namespace specifies the target namespace for the @@ -726,8 +878,9 @@ spec: namespace-scoped resources that have not set a value for .metadata.namespace type: string server: - description: Server specifies the URL of the target cluster and - must be set to the Kubernetes control plane API + description: Server specifies the URL of the target cluster's + Kubernetes control plane API. This must be set if Name is not + set. type: string type: object ignoreDifferences: @@ -927,8 +1080,15 @@ spec: type: array values: description: Values specifies Helm values to be passed to - helm template, typically defined as a block + helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be passed + to helm template, defined as a map. This takes precedence + over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -943,12 +1103,22 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether to + apply env variables substitution for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -965,6 +1135,10 @@ spec: definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether to apply + common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -973,6 +1147,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize adds + to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas override + specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -1180,8 +1408,15 @@ spec: type: array values: description: Values specifies Helm values to be passed to - helm template, typically defined as a block + helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be passed + to helm template, defined as a map. This takes precedence + over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -1196,12 +1431,22 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -1219,6 +1464,10 @@ spec: definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether to apply + common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -1227,6 +1476,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas override + specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -1319,7 +1622,7 @@ spec: as part of automated sync (default: false)' type: boolean selfHeal: - description: 'SelfHeal specifes whether to revert resources + description: 'SelfHeal specifies whether to revert resources back to their desired state upon modification in the cluster (default: false)' type: boolean @@ -1383,7 +1686,7 @@ spec: conditions items: description: ApplicationCondition contains details about an application - condition, which is usally an error or warning + condition, which is usually an error or warning properties: lastTransitionTime: description: LastTransitionTime is the time the condition was @@ -1402,6 +1705,10 @@ spec: - type type: object type: array + controllerNamespace: + description: ControllerNamespace indicates the namespace in which + the application controller is located + type: string health: description: Health contains information about the application's current health status @@ -1435,6 +1742,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 @@ -1581,8 +1901,15 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. ValuesObject + takes precedence over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to be + passed to helm template, defined as a map. This takes + precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -1597,12 +1924,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -1621,6 +1959,10 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -1629,6 +1971,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -1846,8 +2242,16 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. + ValuesObject takes precedence over Values, so use + one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to + be passed to helm template, defined as a map. This + takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -1862,12 +2266,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -1886,6 +2301,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -1894,6 +2314,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -2256,8 +2730,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined as - a block + a block. ValuesObject takes precedence over + Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as a + map. This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -2272,12 +2753,24 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution + for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -2296,6 +2789,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors + or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -2304,14 +2802,68 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string - version: - description: Version controls which version of - Kustomize to use for rendering manifests + namespace: + description: Namespace sets the namespace that + Kustomize adds to all resources type: string - type: object - path: - description: Path is a directory path within the Git - repository, and is only valid for applications sourced + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array + version: + description: Version controls which version of + Kustomize to use for rendering manifests + type: string + type: object + path: + description: Path is a directory path within the Git + repository, and is only valid for applications sourced from Git. type: string plugin: @@ -2537,8 +3089,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined - as a block + as a block. ValuesObject takes precedence + over Values, so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as + a map. This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -2555,12 +3114,24 @@ spec: additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution + for annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -2579,6 +3150,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies + whether to apply common labels to resource + selectors or not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -2587,6 +3163,61 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that + Kustomize adds to all resources + type: string + patches: + description: Patches is a list of Kustomize + patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize + Replicas override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -2720,6 +3351,19 @@ spec: syncResult: description: SyncResult is the result of a Sync operation properties: + managedNamespaceMetadata: + description: ManagedNamespaceMetadata contains the current + sync state of managed namespace metadata + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object resources: description: Resources contains a list of sync result items for each individual resource in a sync operation @@ -2922,8 +3566,16 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. + ValuesObject takes precedence over Values, so use + one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to + be passed to helm template, defined as a map. This + takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -2938,12 +3590,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -2962,6 +3625,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -2970,6 +3638,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -3198,8 +3920,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined as - a block + a block. ValuesObject takes precedence over Values, + so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as a map. + This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -3214,12 +3943,24 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution for + annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -3238,6 +3979,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -3246,6 +3992,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -3428,7 +4228,8 @@ spec: properties: name: description: Name is an alternate way of specifying the - target cluster by its symbolic name + target cluster by its symbolic name. This must be set + if Server is not set. type: string namespace: description: Namespace specifies the target namespace @@ -3437,10 +4238,47 @@ spec: not set a value for .metadata.namespace type: string server: - description: Server specifies the URL of the target cluster - and must be set to the Kubernetes control plane API + description: Server specifies the URL of the target cluster's + Kubernetes control plane API. This must be set if Name + is not set. type: string type: object + ignoreDifferences: + description: IgnoreDifferences is a reference to the application's + ignored differences used for comparison + items: + description: ResourceIgnoreDifferences contains resource + filter and list of json paths which should be ignored + during comparison with live state. + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + description: ManagedFieldsManagers is a list of trusted + managers. Fields mutated by those managers will take + precedence over the desired state defined in the SCM + and won't be displayed in diffs + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array source: description: Source is a reference to the application's source used for comparison @@ -3579,8 +4417,16 @@ spec: type: array values: description: Values specifies Helm values to be passed - to helm template, typically defined as a block + to helm template, typically defined as a block. + ValuesObject takes precedence over Values, so use + one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values to + be passed to helm template, defined as a map. This + takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -3595,12 +4441,23 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies whether + to apply env variables substitution for annotation + values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -3619,6 +4476,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -3627,6 +4489,60 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources + type: string + patches: + description: Patches is a list of Kustomize patches + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array version: description: Version controls which version of Kustomize to use for rendering manifests @@ -3855,8 +4771,15 @@ spec: values: description: Values specifies Helm values to be passed to helm template, typically defined as - a block + a block. ValuesObject takes precedence over Values, + so use one or the other. type: string + valuesObject: + description: ValuesObject specifies Helm values + to be passed to helm template, defined as a map. + This takes precedence over Values. + type: object + x-kubernetes-preserve-unknown-fields: true version: description: Version is the Helm version to use for templating ("3") @@ -3871,12 +4794,24 @@ spec: description: CommonAnnotations is a list of additional annotations to add to rendered manifests type: object + commonAnnotationsEnvsubst: + description: CommonAnnotationsEnvsubst specifies + whether to apply env variables substitution for + annotation values + type: boolean commonLabels: additionalProperties: type: string 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 @@ -3895,6 +4830,11 @@ spec: image definition in the format [old_image_name=]: type: string type: array + labelWithoutSelector: + description: LabelWithoutSelector specifies whether + to apply common labels to resource selectors or + not + type: boolean namePrefix: description: NamePrefix is a prefix appended to resources for Kustomize apps @@ -3903,33 +4843,87 @@ spec: description: NameSuffix is a suffix appended to resources for Kustomize apps type: string - version: - description: Version controls which version of Kustomize - to use for rendering manifests + namespace: + description: Namespace sets the namespace that Kustomize + adds to all resources type: string - type: object - path: - description: Path is a directory path within the Git - repository, and is only valid for applications sourced - from Git. - type: string - plugin: - description: Plugin holds config management plugin specific - options - properties: - env: - description: Env is a list of environment variable - entries + patches: + description: Patches is a list of Kustomize patches items: - description: EnvEntry represents an entry in the - application's environment properties: - name: - description: Name is the name of the variable, - usually expressed in uppercase + options: + additionalProperties: + type: boolean + type: object + patch: type: string - value: - description: Value is the value of the variable + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + description: Replicas is a list of Kustomize Replicas + override specifications + items: + properties: + count: + anyOf: + - type: integer + - type: string + description: Number of replicas + x-kubernetes-int-or-string: true + name: + description: Name of Deployment or StatefulSet + type: string + required: + - count + - name + type: object + type: array + version: + description: Version controls which version of Kustomize + to use for rendering manifests + type: string + type: object + path: + description: Path is a directory path within the Git + repository, and is only valid for applications sourced + from Git. + type: string + plugin: + description: Plugin holds config management plugin specific + options + properties: + env: + description: Env is a list of environment variable + entries + items: + description: EnvEntry represents an entry in the + application's environment + properties: + name: + description: Name is the name of the variable, + usually expressed in uppercase + type: string + value: + description: Value is the value of the variable type: string required: - name @@ -4043,6 +5037,8 @@ spec: type: object spec: properties: + applyNestedSelectors: + type: boolean generators: items: properties: @@ -4238,6 +5234,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4247,10 +5246,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4259,10 +5264,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4396,6 +5450,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4405,10 +5462,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4417,10 +5480,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4713,6 +5825,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4722,10 +5837,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4734,10 +5855,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -4871,6 +6041,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -4880,10 +6053,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4892,10 +6071,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5192,6 +6420,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5201,10 +6432,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5213,10 +6450,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5350,6 +6636,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5359,10 +6648,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5371,25 +6666,74 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string - version: + namespace: type: string - type: object - path: - type: string - plugin: - properties: - env: + patches: items: properties: - name: + options: + additionalProperties: + type: boolean + type: object + patch: type: string - value: + path: type: string - required: + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: - name - value type: object @@ -5475,6 +6819,10 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object required: - repoURL - revision @@ -5485,6 +6833,8 @@ spec: items: x-kubernetes-preserve-unknown-fields: true type: array + elementsYaml: + type: string template: properties: metadata: @@ -5645,6 +6995,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5654,10 +7007,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5666,10 +7025,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5803,6 +7211,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -5812,10 +7223,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5824,10 +7241,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -5928,8 +7394,6 @@ spec: - metadata - spec type: object - required: - - elements type: object matrix: properties: @@ -6128,6 +7592,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6137,10 +7604,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6149,10 +7622,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -6286,6 +7808,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6295,10 +7820,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6307,10 +7838,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -6603,6 +8183,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6612,10 +8195,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6624,10 +8213,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -6761,6 +8399,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -6770,10 +8411,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6782,10 +8429,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7082,6 +8778,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7091,10 +8790,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7103,10 +8808,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7240,6 +8994,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7249,10 +9006,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7261,10 +9024,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7365,6 +9177,10 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object required: - repoURL - revision @@ -7375,6 +9191,8 @@ spec: items: x-kubernetes-preserve-unknown-fields: true type: array + elementsYaml: + type: string template: properties: metadata: @@ -7535,6 +9353,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7544,10 +9365,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7556,10 +9383,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7693,6 +9569,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -7702,10 +9581,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7714,10 +9599,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -7818,153 +9752,49 @@ spec: - metadata - spec type: object - required: - - elements type: object matrix: x-kubernetes-preserve-unknown-fields: true merge: x-kubernetes-preserve-unknown-fields: true - pullRequest: + plugin: properties: - bitbucketServer: + configMapRef: properties: - api: - type: string - basicAuth: - properties: - passwordRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - username: - type: string - required: - - passwordRef - - username - type: object - project: - type: string - repo: + name: type: string required: - - api - - project - - repo + - name type: object - filters: - items: - properties: - branchMatch: - type: string - type: object - type: array - gitea: + input: properties: - api: - type: string - insecure: - type: boolean - owner: - type: string - repo: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName + parameters: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true type: object - required: - - api - - owner - - repo type: object - github: + requeueAfterSeconds: + format: int64 + type: integer + template: properties: - api: - type: string - appSecretName: - type: string - labels: - items: - type: string - type: array - owner: - type: string - repo: - type: string - tokenRef: + metadata: properties: - key: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - owner - - repo - type: object - gitlab: - properties: - api: - type: string - labels: - items: - type: string - type: array - project: - type: string - pullRequestState: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - project - type: object - requeueAfterSeconds: - format: int64 - type: integer - template: - properties: - metadata: - properties: - annotations: - additionalProperties: - type: string - type: object - finalizers: - items: - type: string - type: array - labels: - additionalProperties: - type: string - type: object - name: - type: string - namespace: + namespace: type: string type: object spec: @@ -8106,6 +9936,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8115,10 +9948,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8127,10 +9966,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -8264,6 +10152,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8273,10 +10164,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8285,10 +10182,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -8389,12 +10335,30 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object + required: + - configMapRef type: object - scmProvider: + pullRequest: properties: - azureDevOps: + azuredevops: properties: - accessTokenRef: + api: + type: string + labels: + items: + type: string + type: array + organization: + type: string + project: + type: string + repo: + type: string + tokenRef: properties: key: type: string @@ -8404,46 +10368,58 @@ spec: - key - secretName type: object - allBranches: - type: boolean - api: - type: string - organization: - type: string - teamProject: - type: string required: - - accessTokenRef - organization - - teamProject + - project + - repo type: object bitbucket: properties: - allBranches: - type: boolean - appPasswordRef: + api: + type: string + basicAuth: properties: - key: - type: string - secretName: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: type: string required: - - key - - secretName + - passwordRef + - username + type: object + bearerToken: + properties: + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - tokenRef type: object owner: type: string - user: + repo: type: string required: - - appPasswordRef - owner - - user + - repo type: object bitbucketServer: properties: - allBranches: - type: boolean api: type: string basicAuth: @@ -8466,41 +10442,32 @@ spec: type: object project: type: string + repo: + type: string required: - api - project + - repo type: object - cloneProtocol: - type: string filters: items: properties: branchMatch: type: string - labelMatch: - type: string - pathsDoNotExist: - items: - type: string - type: array - pathsExist: - items: - type: string - type: array - repositoryMatch: + targetBranchMatch: type: string type: object type: array gitea: properties: - allBranches: - type: boolean api: type: string insecure: type: boolean owner: type: string + repo: + type: string tokenRef: properties: key: @@ -8514,16 +10481,21 @@ spec: required: - api - owner + - repo type: object github: properties: - allBranches: - type: boolean api: type: string appSecretName: type: string - organization: + labels: + items: + type: string + type: array + owner: + type: string + repo: type: string tokenRef: properties: @@ -8536,18 +10508,23 @@ spec: - secretName type: object required: - - organization + - owner + - repo type: object gitlab: properties: - allBranches: - type: boolean api: type: string - group: - type: string - includeSubgroups: + insecure: type: boolean + labels: + items: + type: string + type: array + project: + type: string + pullRequestState: + type: string tokenRef: properties: key: @@ -8559,7 +10536,7 @@ spec: - secretName type: object required: - - group + - project type: object requeueAfterSeconds: format: int64 @@ -8724,6 +10701,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8733,10 +10713,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8745,23 +10731,72 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string - version: + namespace: type: string - type: object - path: - type: string - plugin: - properties: - env: + patches: items: properties: - name: - type: string - value: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: type: string required: - name @@ -8882,6 +10917,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -8891,10 +10929,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8903,10 +10947,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -9008,511 +11101,203 @@ spec: - spec type: object type: object - selector: + scmProvider: properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - type: string - values: - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - type: object - type: object - type: object - type: array - template: - properties: - metadata: - properties: - annotations: - additionalProperties: - type: string - type: object - finalizers: - items: - type: string - type: array - labels: - additionalProperties: - type: string - type: object - name: - type: string - namespace: - type: string - type: object - spec: - properties: - destination: - properties: - name: - type: string - namespace: - type: string - server: - type: string - type: object - ignoreDifferences: - items: + awsCodeCommit: properties: - group: + allBranches: + type: boolean + region: type: string - jqPathExpressions: - items: - type: string - type: array - jsonPointers: - items: - type: string - type: array - kind: + role: type: string - managedFieldsManagers: + tagFilters: items: - type: string + properties: + key: + type: string + value: + type: string + required: + - key + type: object type: array - name: + type: object + azureDevOps: + properties: + accessTokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + allBranches: + type: boolean + api: type: string - namespace: + organization: + type: string + teamProject: type: string required: - - kind + - accessTokenRef + - organization + - teamProject type: object - type: array - info: - items: + bitbucket: properties: - name: + allBranches: + type: boolean + appPasswordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + owner: type: string - value: + user: type: string required: - - name - - value + - appPasswordRef + - owner + - user type: object - type: array - project: - type: string - revisionHistoryLimit: - format: int64 - type: integer - source: - properties: - chart: - type: string - directory: + bitbucketServer: + properties: + allBranches: + type: boolean + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + project: + type: string + required: + - api + - project + type: object + cloneProtocol: + type: string + filters: + items: properties: - exclude: + branchMatch: type: string - include: + labelMatch: type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean - type: object - helm: - properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: - type: boolean - valueFiles: + pathsDoNotExist: items: type: string type: array - values: - type: string - version: - type: string - type: object - kustomize: - properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: - type: boolean - images: + pathsExist: items: type: string type: array - namePrefix: - type: string - nameSuffix: - type: string - version: - type: string - type: object - path: - type: string - plugin: - properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - name: + repositoryMatch: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array type: object - ref: - type: string - repoURL: - type: string - targetRevision: - type: string - required: - - repoURL - type: object - sources: - items: + type: array + gitea: properties: - chart: + allBranches: + type: boolean + api: type: string - directory: + insecure: + type: boolean + owner: + type: string + tokenRef: properties: - exclude: + key: type: string - include: + secretName: type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean + required: + - key + - secretName type: object - helm: + required: + - api + - owner + type: object + github: + properties: + allBranches: + type: boolean + api: + type: string + appSecretName: + type: string + organization: + type: string + tokenRef: properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: - type: boolean - valueFiles: - items: - type: string - type: array - values: + key: type: string - version: + secretName: type: string + required: + - key + - secretName type: object - kustomize: - properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: - type: boolean - images: - items: - type: string - type: array - namePrefix: - type: string - nameSuffix: - type: string - version: - type: string - type: object - path: + required: + - organization + type: object + gitlab: + properties: + allBranches: + type: boolean + api: type: string - plugin: + group: + type: string + includeSharedProjects: + type: boolean + includeSubgroups: + type: boolean + insecure: + type: boolean + tokenRef: properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - name: + key: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array + secretName: + type: string + required: + - key + - secretName type: object - ref: - type: string - repoURL: - type: string - targetRevision: + topic: type: string required: - - repoURL - type: object - type: array - syncPolicy: - properties: - automated: - properties: - allowEmpty: - type: boolean - prune: - type: boolean - selfHeal: - type: boolean - type: object - managedNamespaceMetadata: - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - retry: - properties: - backoff: - properties: - duration: - type: string - factor: - format: int64 - type: integer - maxDuration: - type: string - type: object - limit: - format: int64 - type: integer - type: object - syncOptions: - items: - type: string - type: array - type: object - required: - - destination - - project - type: object - required: - - metadata - - spec - type: object - required: - - generators - type: object - merge: - properties: - generators: - items: - properties: - clusterDecisionResource: - properties: - configMapRef: - type: string - labelSelector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - type: string - values: - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - type: object + - group type: object - name: - type: string requeueAfterSeconds: format: int64 type: integer @@ -9676,6 +11461,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -9685,10 +11473,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9697,10 +11491,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -9834,6 +11677,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -9843,10 +11689,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9855,10 +11707,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -9963,34 +11864,2392 @@ spec: additionalProperties: type: string type: object - required: - - configMapRef type: object - clusters: + selector: properties: - selector: - properties: - matchExpressions: - items: - properties: - key: - type: string - operator: - type: string - values: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + type: object + type: array + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: items: type: string type: array - required: - - key - - operator + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array type: object - type: array - matchLabels: - additionalProperties: + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + required: + - generators + type: object + merge: + properties: + generators: + items: + properties: + clusterDecisionResource: + properties: + configMapRef: + type: string + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + name: + type: string + requeueAfterSeconds: + format: int64 + type: integer + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + required: + - configMapRef + type: object + clusters: + properties: + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + type: object + git: + properties: + directories: + items: + properties: + exclude: + type: boolean + path: + type: string + required: + - path + type: object + type: array + files: + items: + properties: + path: + type: string + required: + - path + type: object + type: array + pathParamPrefix: + type: string + repoURL: + type: string + requeueAfterSeconds: + format: int64 + type: integer + revision: + type: string + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: + type: string + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + kind: + type: string + managedFieldsManagers: + items: + type: string + type: array + name: + type: string + namespace: + type: string + required: + - kind + type: object + type: array + info: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + libs: + items: + type: string + type: array + tlas: + items: + properties: + code: + type: boolean + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string + path: + type: string + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + type: array + syncPolicy: + properties: + automated: + properties: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: + type: string + type: object + labels: + additionalProperties: + type: string + type: object + type: object + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string type: object + required: + - repoURL + - revision + type: object + list: + properties: + elements: + items: + x-kubernetes-preserve-unknown-fields: true + type: array + elementsYaml: + type: string template: properties: metadata: @@ -10151,6 +14410,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10160,10 +14422,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10172,10 +14440,59 @@ spec: items: type: string type: array - namePrefix: - type: string - nameSuffix: - type: string + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10309,6 +14626,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10318,10 +14638,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10330,10 +14656,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10434,42 +14809,30 @@ spec: - metadata - spec type: object - values: - additionalProperties: - type: string - type: object type: object - git: + matrix: + x-kubernetes-preserve-unknown-fields: true + merge: + x-kubernetes-preserve-unknown-fields: true + plugin: properties: - directories: - items: - properties: - exclude: - type: boolean - path: - type: string - required: - - path - type: object - type: array - files: - items: - properties: - path: - type: string - required: - - path - type: object - type: array - pathParamPrefix: - type: string - repoURL: - type: string + configMapRef: + properties: + name: + type: string + required: + - name + type: object + input: + properties: + parameters: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object requeueAfterSeconds: format: int64 type: integer - revision: - type: string template: properties: metadata: @@ -10630,6 +14993,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10639,10 +15005,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10651,10 +15023,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10788,6 +15209,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -10797,10 +15221,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10809,10 +15239,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -10906,23 +15385,219 @@ spec: type: array type: object required: - - destination - - project + - destination + - project + type: object + required: + - metadata + - spec + type: object + values: + additionalProperties: + type: string + type: object + required: + - configMapRef + type: object + pullRequest: + properties: + azuredevops: + properties: + api: + type: string + labels: + items: + type: string + type: array + organization: + type: string + project: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - organization + - project + - repo + type: object + bitbucket: + properties: + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + bearerToken: + properties: + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - tokenRef + type: object + owner: + type: string + repo: + type: string + required: + - owner + - repo + type: object + bitbucketServer: + properties: + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username type: object + project: + type: string + repo: + type: string required: - - metadata - - spec + - api + - project + - repo type: object - required: - - repoURL - - revision - type: object - list: - properties: - elements: + filters: items: - x-kubernetes-preserve-unknown-fields: true + properties: + branchMatch: + type: string + targetBranchMatch: + type: string + type: object type: array + gitea: + properties: + api: + type: string + insecure: + type: boolean + owner: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - api + - owner + - repo + type: object + github: + properties: + api: + type: string + appSecretName: + type: string + labels: + items: + type: string + type: array + owner: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - owner + - repo + type: object + gitlab: + properties: + api: + type: string + insecure: + type: boolean + labels: + items: + type: string + type: array + project: + type: string + pullRequestState: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - project + type: object + requeueAfterSeconds: + format: int64 + type: integer template: properties: metadata: @@ -11083,6 +15758,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -11092,10 +15770,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11104,10 +15788,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -11241,6 +15974,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -11250,10 +15986,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11262,10 +16004,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -11366,17 +16157,81 @@ spec: - metadata - spec type: object - required: - - elements type: object - matrix: - x-kubernetes-preserve-unknown-fields: true - merge: - x-kubernetes-preserve-unknown-fields: true - pullRequest: + scmProvider: properties: + awsCodeCommit: + properties: + allBranches: + type: boolean + region: + type: string + role: + type: string + tagFilters: + items: + properties: + key: + type: string + value: + type: string + required: + - key + type: object + type: array + type: object + azureDevOps: + properties: + accessTokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + allBranches: + type: boolean + api: + type: string + organization: + type: string + teamProject: + type: string + required: + - accessTokenRef + - organization + - teamProject + type: object + bitbucket: + properties: + allBranches: + type: boolean + appPasswordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + owner: + type: string + user: + type: string + required: + - appPasswordRef + - owner + - user + type: object bitbucketServer: properties: + allBranches: + type: boolean api: type: string basicAuth: @@ -11399,30 +16254,41 @@ spec: type: object project: type: string - repo: - type: string required: - api - project - - repo type: object + cloneProtocol: + type: string filters: items: properties: branchMatch: type: string + labelMatch: + type: string + pathsDoNotExist: + items: + type: string + type: array + pathsExist: + items: + type: string + type: array + repositoryMatch: + type: string type: object type: array gitea: properties: + allBranches: + type: boolean api: type: string insecure: type: boolean owner: type: string - repo: - type: string tokenRef: properties: key: @@ -11436,21 +16302,16 @@ spec: required: - api - owner - - repo type: object github: properties: + allBranches: + type: boolean api: type: string appSecretName: type: string - labels: - items: - type: string - type: array - owner: - type: string - repo: + organization: type: string tokenRef: properties: @@ -11463,21 +16324,22 @@ spec: - secretName type: object required: - - owner - - repo + - organization type: object gitlab: properties: + allBranches: + type: boolean api: type: string - labels: - items: - type: string - type: array - project: - type: string - pullRequestState: + group: type: string + includeSharedProjects: + type: boolean + includeSubgroups: + type: boolean + insecure: + type: boolean tokenRef: properties: key: @@ -11488,8 +16350,10 @@ spec: - key - secretName type: object + topic: + type: string required: - - project + - group type: object requeueAfterSeconds: format: int64 @@ -11654,6 +16518,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -11663,10 +16530,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11675,10 +16548,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -11812,6 +16734,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -11821,10 +16746,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11833,10 +16764,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -11937,654 +16917,622 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object type: object - scmProvider: + selector: properties: - azureDevOps: - properties: - accessTokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - allBranches: - type: boolean - api: - type: string - organization: - type: string - teamProject: - type: string - required: - - accessTokenRef - - organization - - teamProject - type: object - bitbucket: - properties: - allBranches: - type: boolean - appPasswordRef: - properties: - key: - type: string - secretName: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: type: string - required: - - key - - secretName - type: object - owner: - type: string - user: - type: string - required: - - appPasswordRef - - owner - - user + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string type: object - bitbucketServer: - properties: - allBranches: - type: boolean - api: - type: string - basicAuth: - properties: - passwordRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - username: - type: string - required: - - passwordRef - - username - type: object - project: + type: object + type: object + type: array + mergeKeys: + items: + type: string + type: array + template: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + properties: + destination: + properties: + name: + type: string + namespace: + type: string + server: + type: string + type: object + ignoreDifferences: + items: + properties: + group: type: string - required: - - api - - project - type: object - cloneProtocol: - type: string - filters: - items: - properties: - branchMatch: - type: string - labelMatch: + jqPathExpressions: + items: type: string - pathsDoNotExist: - items: - type: string - type: array - pathsExist: - items: - type: string - type: array - repositoryMatch: + type: array + jsonPointers: + items: type: string - type: object - type: array - gitea: - properties: - allBranches: - type: boolean - api: - type: string - insecure: - type: boolean - owner: - type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object - required: - - api - - owner - type: object - github: - properties: - allBranches: - type: boolean - api: + type: array + kind: type: string - appSecretName: + managedFieldsManagers: + items: + type: string + type: array + name: type: string - organization: + namespace: type: string - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object required: - - organization + - kind type: object - gitlab: + type: array + info: + items: properties: - allBranches: - type: boolean - api: + name: type: string - group: + value: type: string - includeSubgroups: - type: boolean - tokenRef: - properties: - key: - type: string - secretName: - type: string - required: - - key - - secretName - type: object required: - - group + - name + - value type: object - requeueAfterSeconds: - format: int64 - type: integer - template: - properties: - metadata: - properties: - annotations: - additionalProperties: - type: string - type: object - finalizers: - items: - type: string - type: array - labels: - additionalProperties: - type: string - type: object - name: - type: string - namespace: - type: string - type: object - spec: - properties: - destination: - properties: - name: - type: string - namespace: - type: string - server: - type: string - type: object - ignoreDifferences: - items: - properties: - group: - type: string - jqPathExpressions: - items: - type: string - type: array - jsonPointers: - items: - type: string - type: array - kind: - type: string - managedFieldsManagers: - items: - type: string - type: array - name: - type: string - namespace: - type: string - required: - - kind - type: object - type: array - info: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - project: - type: string - revisionHistoryLimit: - format: int64 - type: integer - source: - properties: - chart: - type: string - directory: - properties: - exclude: - type: string - include: - type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean - type: object - helm: + type: array + project: + type: string + revisionHistoryLimit: + format: int64 + type: integer + source: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: + code: type: boolean - valueFiles: - items: - type: string - type: array - values: + name: type: string - version: + value: type: string + required: + - name + - value type: object - kustomize: + type: array + libs: + items: + type: string + type: array + tlas: + items: properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: + code: type: boolean - images: - items: - type: string - type: array - namePrefix: - type: string - nameSuffix: + name: type: string - version: + value: type: string + required: + - name + - value type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string path: type: string - plugin: + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string name: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array + namespace: + type: string + version: + type: string type: object - ref: - type: string - repoURL: - type: string - targetRevision: + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: type: string required: - - repoURL - type: object - sources: - items: - properties: - chart: - type: string - directory: - properties: - exclude: - type: string - include: - type: string - jsonnet: - properties: - extVars: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - libs: - items: - type: string - type: array - tlas: - items: - properties: - code: - type: boolean - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array - type: object - recurse: - type: boolean - type: object - helm: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: + type: string + string: + type: string + type: object + type: array + type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string + required: + - repoURL + type: object + sources: + items: + properties: + chart: + type: string + directory: + properties: + exclude: + type: string + include: + type: string + jsonnet: + properties: + extVars: + items: properties: - fileParameters: - items: - properties: - name: - type: string - path: - type: string - type: object - type: array - ignoreMissingValueFiles: - type: boolean - parameters: - items: - properties: - forceString: - type: boolean - name: - type: string - value: - type: string - type: object - type: array - passCredentials: - type: boolean - releaseName: - type: string - skipCrds: + code: type: boolean - valueFiles: - items: - type: string - type: array - values: + name: type: string - version: + value: type: string + required: + - name + - value type: object - kustomize: + type: array + libs: + items: + type: string + type: array + tlas: + items: properties: - commonAnnotations: - additionalProperties: - type: string - type: object - commonLabels: - additionalProperties: - type: string - type: object - forceCommonAnnotations: - type: boolean - forceCommonLabels: + code: type: boolean - images: - items: - type: string - type: array - namePrefix: - type: string - nameSuffix: + name: type: string - version: + value: type: string + required: + - name + - value type: object + type: array + type: object + recurse: + type: boolean + type: object + helm: + properties: + fileParameters: + items: + properties: + name: + type: string path: type: string - plugin: + type: object + type: array + ignoreMissingValueFiles: + type: boolean + parameters: + items: + properties: + forceString: + type: boolean + name: + type: string + value: + type: string + type: object + type: array + passCredentials: + type: boolean + releaseName: + type: string + skipCrds: + type: boolean + valueFiles: + items: + type: string + type: array + values: + type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true + version: + type: string + type: object + kustomize: + properties: + commonAnnotations: + additionalProperties: + type: string + type: object + commonAnnotationsEnvsubst: + type: boolean + commonLabels: + additionalProperties: + type: string + type: object + components: + items: + type: string + type: array + forceCommonAnnotations: + type: boolean + forceCommonLabels: + type: boolean + images: + items: + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: properties: - env: - items: - properties: - name: - type: string - value: - type: string - required: - - name - - value - type: object - type: array + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string name: type: string - parameters: - items: - properties: - array: - items: - type: string - type: array - map: - additionalProperties: - type: string - type: object - name: - type: string - string: - type: string - type: object - type: array + namespace: + type: string + version: + type: string type: object - ref: + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: type: string - repoURL: + required: + - count + - name + type: object + type: array + version: + type: string + type: object + path: + type: string + plugin: + properties: + env: + items: + properties: + name: type: string - targetRevision: + value: type: string required: - - repoURL + - name + - value type: object type: array - syncPolicy: - properties: - automated: - properties: - allowEmpty: - type: boolean - prune: - type: boolean - selfHeal: - type: boolean - type: object - managedNamespaceMetadata: - properties: - annotations: - additionalProperties: - type: string - type: object - labels: - additionalProperties: - type: string - type: object - type: object - retry: - properties: - backoff: - properties: - duration: - type: string - factor: - format: int64 - type: integer - maxDuration: - type: string - type: object - limit: - format: int64 - type: integer - type: object - syncOptions: - items: + name: + type: string + parameters: + items: + properties: + array: + items: + type: string + type: array + map: + additionalProperties: + type: string + type: object + name: type: string - type: array - type: object - required: - - destination - - project + string: + type: string + type: object + type: array type: object + ref: + type: string + repoURL: + type: string + targetRevision: + type: string required: - - metadata - - spec + - repoURL type: object - type: object - selector: - properties: - matchExpressions: - items: + type: array + syncPolicy: + properties: + automated: properties: - key: - type: string - operator: - type: string - values: - items: + allowEmpty: + type: boolean + prune: + type: boolean + selfHeal: + type: boolean + type: object + managedNamespaceMetadata: + properties: + annotations: + additionalProperties: type: string - type: array - required: - - key - - operator + type: object + labels: + additionalProperties: + type: string + type: object type: object - type: array - matchLabels: - additionalProperties: - type: string - type: object - type: object - type: object - type: array - mergeKeys: - items: - type: string - type: array + retry: + properties: + backoff: + properties: + duration: + type: string + factor: + format: int64 + type: integer + maxDuration: + type: string + type: object + limit: + format: int64 + type: integer + type: object + syncOptions: + items: + type: string + type: array + type: object + required: + - destination + - project + type: object + required: + - metadata + - spec + type: object + required: + - generators + - mergeKeys + type: object + plugin: + properties: + configMapRef: + properties: + name: + type: string + required: + - name + type: object + input: + properties: + parameters: + additionalProperties: + x-kubernetes-preserve-unknown-fields: true + type: object + type: object + requeueAfterSeconds: + format: int64 + type: integer template: properties: metadata: @@ -12745,6 +17693,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -12754,10 +17705,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12766,10 +17723,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -12903,6 +17909,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -12912,22 +17921,77 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: type: boolean images: items: - type: string + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object type: array - namePrefix: - type: string - nameSuffix: - type: string version: type: string type: object @@ -13028,12 +18092,89 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object required: - - generators - - mergeKeys + - configMapRef type: object pullRequest: properties: + azuredevops: + properties: + api: + type: string + labels: + items: + type: string + type: array + organization: + type: string + project: + type: string + repo: + type: string + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - organization + - project + - repo + type: object + bitbucket: + properties: + api: + type: string + basicAuth: + properties: + passwordRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + username: + type: string + required: + - passwordRef + - username + type: object + bearerToken: + properties: + tokenRef: + properties: + key: + type: string + secretName: + type: string + required: + - key + - secretName + type: object + required: + - tokenRef + type: object + owner: + type: string + repo: + type: string + required: + - owner + - repo + type: object bitbucketServer: properties: api: @@ -13070,6 +18211,8 @@ spec: properties: branchMatch: type: string + targetBranchMatch: + type: string type: object type: array gitea: @@ -13129,6 +18272,8 @@ spec: properties: api: type: string + insecure: + type: boolean labels: items: type: string @@ -13313,6 +18458,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -13322,10 +18470,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13334,10 +18488,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -13471,6 +18674,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -13480,10 +18686,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13492,10 +18704,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -13599,6 +18860,26 @@ spec: type: object scmProvider: properties: + awsCodeCommit: + properties: + allBranches: + type: boolean + region: + type: string + role: + type: string + tagFilters: + items: + properties: + key: + type: string + value: + type: string + required: + - key + type: object + type: array + type: object azureDevOps: properties: accessTokenRef: @@ -13753,8 +19034,12 @@ spec: type: string group: type: string + includeSharedProjects: + type: boolean includeSubgroups: type: boolean + insecure: + type: boolean tokenRef: properties: key: @@ -13765,6 +19050,8 @@ spec: - key - secretName type: object + topic: + type: string required: - group type: object @@ -13931,6 +19218,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -13940,10 +19230,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13952,10 +19248,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -14089,6 +19434,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -14098,22 +19446,77 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: type: boolean images: items: - type: string + type: string + type: array + labelWithoutSelector: + type: boolean + namePrefix: + type: string + nameSuffix: + type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object type: array - namePrefix: - type: string - nameSuffix: - type: string version: type: string type: object @@ -14214,6 +19617,10 @@ spec: - metadata - spec type: object + values: + additionalProperties: + type: string + type: object type: object selector: properties: @@ -14242,6 +19649,36 @@ spec: type: array goTemplate: type: boolean + goTemplateOptions: + items: + type: string + type: array + ignoreApplicationDifferences: + items: + properties: + jqPathExpressions: + items: + type: string + type: array + jsonPointers: + items: + type: string + type: array + name: + type: string + type: object + type: array + preservedFields: + properties: + annotations: + items: + type: string + type: array + labels: + items: + type: string + type: array + type: object strategy: properties: rollingSync: @@ -14275,6 +19712,13 @@ spec: type: object syncPolicy: properties: + applicationsSync: + enum: + - create-only + - create-update + - create-delete + - sync + type: string preserveResourcesOnDeletion: type: boolean type: object @@ -14438,6 +19882,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -14447,10 +19894,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14459,10 +19912,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -14596,6 +20098,9 @@ spec: type: array values: type: string + valuesObject: + type: object + x-kubernetes-preserve-unknown-fields: true version: type: string type: object @@ -14605,10 +20110,16 @@ spec: additionalProperties: type: string type: object + commonAnnotationsEnvsubst: + type: boolean commonLabels: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14617,10 +20128,59 @@ spec: items: type: string type: array + labelWithoutSelector: + type: boolean namePrefix: type: string nameSuffix: type: string + namespace: + type: string + patches: + items: + properties: + options: + additionalProperties: + type: boolean + type: object + patch: + type: string + path: + type: string + target: + properties: + annotationSelector: + type: string + group: + type: string + kind: + type: string + labelSelector: + type: string + name: + type: string + namespace: + type: string + version: + type: string + type: object + type: object + type: array + replicas: + items: + properties: + count: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + name: + type: string + required: + - count + - name + type: object + type: array version: type: string type: object @@ -14721,6 +20281,8 @@ spec: - metadata - spec type: object + templatePatch: + type: string required: - generators - template @@ -14739,10 +20301,13 @@ spec: type: string status: type: string + step: + type: string required: - application - message - status + - step type: object type: array conditions: @@ -14866,7 +20431,8 @@ spec: properties: name: description: Name is an alternate way of specifying the target - cluster by its symbolic name + cluster by its symbolic name. This must be set if Server is + not set. type: string namespace: description: Namespace specifies the target namespace for the @@ -14874,8 +20440,9 @@ spec: namespace-scoped resources that have not set a value for .metadata.namespace type: string server: - description: Server specifies the URL of the target cluster - and must be set to the Kubernetes control plane API + description: Server specifies the URL of the target cluster's + Kubernetes control plane API. This must be set if Name is + not set. type: string type: object type: array @@ -15112,9 +20679,9 @@ apiVersion: v1 kind: ServiceAccount metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller --- apiVersion: v1 @@ -15200,14 +20767,22 @@ rules: verbs: - create - list +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller rules: - apiGroups: @@ -15289,6 +20864,10 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller rules: - apiGroups: @@ -15393,6 +20972,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 @@ -15425,10 +21093,23 @@ rules: - argoproj.io resources: - applications + - applicationsets verbs: - get - list - watch +- apiGroups: + - batch + resources: + - jobs + verbs: + - create +- apiGroups: + - argoproj.io + resources: + - workflows + verbs: + - create --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding @@ -15450,9 +21131,9 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller roleRef: apiGroup: rbac.authorization.k8s.io @@ -15466,45 +21147,33 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: - app.kubernetes.io/component: dex-server - app.kubernetes.io/name: argocd-dex-server - app.kubernetes.io/part-of: argocd - name: argocd-dex-server -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: argocd-dex-server -subjects: -- kind: ServiceAccount - name: argocd-dex-server ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: argocd-notifications-controller + app.kubernetes.io/component: dex-server + app.kubernetes.io/name: argocd-dex-server + app.kubernetes.io/part-of: argocd + name: argocd-dex-server roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: argocd-notifications-controller + name: argocd-dex-server subjects: - kind: ServiceAccount - name: argocd-notifications-controller + name: argocd-dex-server --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: - app.kubernetes.io/component: redis - app.kubernetes.io/name: argocd-redis + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller app.kubernetes.io/part-of: argocd - name: argocd-redis + name: argocd-notifications-controller roleRef: apiGroup: rbac.authorization.k8s.io kind: Role - name: argocd-redis + name: argocd-notifications-controller subjects: - kind: ServiceAccount - name: argocd-redis + name: argocd-notifications-controller --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding @@ -15541,6 +21210,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 @@ -15583,6 +21269,10 @@ metadata: apiVersion: v1 kind: ConfigMap metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-cm --- apiVersion: v1 @@ -15595,16 +21285,22 @@ metadata: --- apiVersion: v1 data: - ssh_known_hosts: |- - bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== - github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== + ssh_known_hosts: | + # This file was automatically generated by hack/update-ssh-known-hosts.sh. DO NOT EDIT + [ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + [ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + [ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= + bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= + bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO + bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M= + github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H - github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= - github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl kind: ConfigMap metadata: labels: @@ -15623,6 +21319,10 @@ metadata: apiVersion: v1 kind: Secret metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-secret type: Opaque --- @@ -15639,9 +21339,9 @@ apiVersion: v1 kind: Service metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller spec: ports: @@ -15666,7 +21366,8 @@ metadata: name: argocd-dex-server spec: ports: - - name: http + - appProtocol: TCP + name: http port: 5556 protocol: TCP targetPort: 5556 @@ -15702,7 +21403,9 @@ apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: notifications-controller app.kubernetes.io/name: argocd-notifications-controller-metrics + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller-metrics spec: ports: @@ -15792,9 +21495,9 @@ apiVersion: apps/v1 kind: Deployment metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller spec: selector: @@ -15806,10 +21509,21 @@ spec: app.kubernetes.io/name: argocd-applicationset-controller spec: containers: - - command: - - entrypoint.sh - - argocd-applicationset-controller + - args: + - /usr/local/bin/argocd-applicationset-controller env: + - name: ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_ANNOTATIONS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.global.preserved.annotations + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_LABELS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.global.preserved.labels + name: argocd-cmd-params-cm + optional: true - name: NAMESPACE valueFrom: fieldRef: @@ -15820,12 +21534,6 @@ spec: key: applicationsetcontroller.enable.leader.election name: argocd-cmd-params-cm optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACE - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.namespace - name: argocd-cmd-params-cm - optional: true - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER valueFrom: configMapKeyRef: @@ -15838,6 +21546,12 @@ spec: key: applicationsetcontroller.policy name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.policy.override + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG valueFrom: configMapKeyRef: @@ -15868,10 +21582,64 @@ spec: key: applicationsetcontroller.enable.git.submodule name: argocd-cmd-params-cm optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.progressive.syncs + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.new.git.file.globbing + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.strict.tls + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.timeout.seconds + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_CONCURRENT_RECONCILIATIONS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.concurrent.reconciliations.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.namespaces + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.scm.root.ca.path + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.allowed.scm.providers + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS valueFrom: configMapKeyRef: - key: applicationsetcontroller.enable.progressive.rollouts + key: applicationsetcontroller.enable.scm.providers name: argocd-cmd-params-cm optional: true image: quay.io/argoproj/argocd:latest @@ -15902,6 +21670,8 @@ spec: name: gpg-keyring - mountPath: /tmp name: tmp + - mountPath: /app/config/reposerver/tls + name: argocd-repo-server-tls serviceAccountName: argocd-applicationset-controller volumes: - configMap: @@ -15917,6 +21687,17 @@ spec: name: gpg-keyring - emptyDir: {} name: tmp + - name: argocd-repo-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-repo-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -15955,7 +21736,7 @@ spec: key: dexserver.disable.tls name: argocd-cmd-params-cm optional: true - image: ghcr.io/dexidp/dex:v2.35.3 + image: ghcr.io/dexidp/dex:v2.38.0 imagePullPolicy: Always name: dex ports: @@ -15980,7 +21761,7 @@ spec: name: argocd-dex-server-tls initContainers: - command: - - cp + - /bin/cp - -n - /usr/local/bin/argocd - /shared/argocd-dex @@ -16022,6 +21803,10 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller spec: selector: @@ -16035,8 +21820,33 @@ spec: app.kubernetes.io/name: argocd-notifications-controller spec: containers: - - command: - - argocd-notifications + - args: + - /usr/local/bin/argocd-notifications + env: + - name: ARGOCD_NOTIFICATIONS_CONTROLLER_LOGFORMAT + valueFrom: + configMapKeyRef: + key: notificationscontroller.log.format + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_NOTIFICATIONS_CONTROLLER_LOGLEVEL + valueFrom: + configMapKeyRef: + key: notificationscontroller.log.level + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_NAMESPACES + valueFrom: + configMapKeyRef: + 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: @@ -16114,7 +21924,7 @@ spec: - "" - --appendonly - "no" - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: Always name: redis ports: @@ -16124,6 +21934,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true securityContext: runAsNonRoot: true runAsUser: 999 @@ -16165,10 +21976,8 @@ spec: weight: 5 automountServiceAccountToken: false containers: - - command: - - sh - - -c - - entrypoint.sh argocd-repo-server --redis argocd-redis:6379 + - args: + - /usr/local/bin/argocd-repo-server env: - name: ARGOCD_RECONCILIATION_TIMEOUT valueFrom: @@ -16194,6 +22003,18 @@ spec: key: reposerver.parallelism.limit name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: reposerver.listen.address + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_LISTEN_METRICS_ADDRESS + valueFrom: + configMapKeyRef: + key: reposerver.metrics.listen.address + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_REPO_SERVER_DISABLE_TLS valueFrom: configMapKeyRef: @@ -16254,6 +22075,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: @@ -16284,12 +22117,42 @@ spec: key: reposerver.streamed.manifest.max.extracted.size name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE + valueFrom: + configMapKeyRef: + key: reposerver.helm.manifest.max.extracted.size + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE + valueFrom: + configMapKeyRef: + key: reposerver.disable.helm.manifest.max.extracted.size + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REVISION_CACHE_LOCK_TIMEOUT + valueFrom: + configMapKeyRef: + key: reposerver.revision.cache.lock.timeout + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_GIT_MODULES_ENABLED valueFrom: configMapKeyRef: 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 @@ -16344,7 +22207,7 @@ spec: name: plugins initContainers: - command: - - cp + - /bin/cp - -n - /usr/local/bin/argocd - /var/run/argocd/argocd-cmp-server @@ -16428,8 +22291,8 @@ spec: topologyKey: kubernetes.io/hostname weight: 5 containers: - - command: - - argocd-server + - args: + - /usr/local/bin/argocd-server env: - name: ARGOCD_SERVER_INSECURE valueFrom: @@ -16605,12 +22468,36 @@ spec: key: server.http.cookie.maxnumber name: argocd-cmd-params-cm optional: true + - name: ARGOCD_SERVER_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: server.listen.address + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_SERVER_METRICS_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: server.metrics.listen.address + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_SERVER_OTLP_ADDRESS valueFrom: configMapKeyRef: 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: @@ -16623,6 +22510,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: @@ -16732,8 +22637,8 @@ spec: topologyKey: kubernetes.io/hostname weight: 5 containers: - - command: - - argocd-application-controller + - args: + - /usr/local/bin/argocd-application-controller env: - name: ARGOCD_CONTROLLER_REPLICAS value: "1" @@ -16749,6 +22654,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: @@ -16851,12 +22768,54 @@ 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: key: application.namespaces name: argocd-cmd-params-cm optional: true + - name: ARGOCD_CONTROLLER_SHARDING_ALGORITHM + valueFrom: + configMapKeyRef: + key: controller.sharding.algorithm + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_KUBECTL_PARALLELISM_LIMIT + valueFrom: + configMapKeyRef: + 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 @@ -16963,6 +22922,10 @@ spec: apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller-network-policy spec: ingress: @@ -17025,6 +22988,9 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-applicationset-controller ports: - port: 8081 protocol: TCP diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 606045c259df2..91826ef8d5620 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -12,9 +12,9 @@ apiVersion: v1 kind: ServiceAccount metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller --- apiVersion: v1 @@ -100,14 +100,22 @@ rules: verbs: - create - list +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller rules: - apiGroups: @@ -189,6 +197,10 @@ rules: apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller rules: - apiGroups: @@ -291,9 +303,9 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller roleRef: apiGroup: rbac.authorization.k8s.io @@ -322,6 +334,10 @@ subjects: apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller roleRef: apiGroup: rbac.authorization.k8s.io @@ -333,22 +349,6 @@ subjects: --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding -metadata: - labels: - app.kubernetes.io/component: redis - app.kubernetes.io/name: argocd-redis - app.kubernetes.io/part-of: argocd - name: argocd-redis -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: argocd-redis -subjects: -- kind: ServiceAccount - name: argocd-redis ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding metadata: labels: app.kubernetes.io/component: server @@ -390,6 +390,10 @@ metadata: apiVersion: v1 kind: ConfigMap metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-cm --- apiVersion: v1 @@ -402,16 +406,22 @@ metadata: --- apiVersion: v1 data: - ssh_known_hosts: |- - bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== - github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== + ssh_known_hosts: | + # This file was automatically generated by hack/update-ssh-known-hosts.sh. DO NOT EDIT + [ssh.github.com]:443 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + [ssh.github.com]:443 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + [ssh.github.com]:443 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= + bitbucket.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPIQmuzMBuKdWeF4+a2sjSSpBK0iqitSQ+5BM9KhpexuGt20JpTVM7u5BDZngncgrqDMbWdxMWWOGtZ9UgbqgZE= + bitbucket.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIazEu89wgQZ4bqs3d63QSMzYVa0MuJ2e2gKTKqu+UUO + bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M= + github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= + github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl + github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H - github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= - github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl kind: ConfigMap metadata: labels: @@ -430,6 +440,10 @@ metadata: apiVersion: v1 kind: Secret metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-secret type: Opaque --- @@ -446,9 +460,9 @@ apiVersion: v1 kind: Service metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller spec: ports: @@ -473,7 +487,8 @@ metadata: name: argocd-dex-server spec: ports: - - name: http + - appProtocol: TCP + name: http port: 5556 protocol: TCP targetPort: 5556 @@ -509,7 +524,9 @@ apiVersion: v1 kind: Service metadata: labels: + app.kubernetes.io/component: notifications-controller app.kubernetes.io/name: argocd-notifications-controller-metrics + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller-metrics spec: ports: @@ -599,9 +616,9 @@ apiVersion: apps/v1 kind: Deployment metadata: labels: - app.kubernetes.io/component: controller + app.kubernetes.io/component: applicationset-controller app.kubernetes.io/name: argocd-applicationset-controller - app.kubernetes.io/part-of: argocd-applicationset + app.kubernetes.io/part-of: argocd name: argocd-applicationset-controller spec: selector: @@ -613,10 +630,21 @@ spec: app.kubernetes.io/name: argocd-applicationset-controller spec: containers: - - command: - - entrypoint.sh - - argocd-applicationset-controller + - args: + - /usr/local/bin/argocd-applicationset-controller env: + - name: ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_ANNOTATIONS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.global.preserved.annotations + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_LABELS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.global.preserved.labels + name: argocd-cmd-params-cm + optional: true - name: NAMESPACE valueFrom: fieldRef: @@ -627,12 +655,6 @@ spec: key: applicationsetcontroller.enable.leader.election name: argocd-cmd-params-cm optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACE - valueFrom: - configMapKeyRef: - key: applicationsetcontroller.namespace - name: argocd-cmd-params-cm - optional: true - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER valueFrom: configMapKeyRef: @@ -645,6 +667,12 @@ spec: key: applicationsetcontroller.policy name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.policy.override + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATIONSET_CONTROLLER_DEBUG valueFrom: configMapKeyRef: @@ -675,10 +703,64 @@ spec: key: applicationsetcontroller.enable.git.submodule name: argocd-cmd-params-cm optional: true - - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_ROLLOUTS + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.progressive.syncs + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.enable.new.git.file.globbing + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_PLAINTEXT + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.plaintext + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_STRICT_TLS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.strict.tls + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.repo.server.timeout.seconds + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_CONCURRENT_RECONCILIATIONS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.concurrent.reconciliations.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.namespaces + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.scm.root.ca.path + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS + valueFrom: + configMapKeyRef: + key: applicationsetcontroller.allowed.scm.providers + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS valueFrom: configMapKeyRef: - key: applicationsetcontroller.enable.progressive.rollouts + key: applicationsetcontroller.enable.scm.providers name: argocd-cmd-params-cm optional: true image: quay.io/argoproj/argocd:latest @@ -709,6 +791,8 @@ spec: name: gpg-keyring - mountPath: /tmp name: tmp + - mountPath: /app/config/reposerver/tls + name: argocd-repo-server-tls serviceAccountName: argocd-applicationset-controller volumes: - configMap: @@ -724,6 +808,17 @@ spec: name: gpg-keyring - emptyDir: {} name: tmp + - name: argocd-repo-server-tls + secret: + items: + - key: tls.crt + path: tls.crt + - key: tls.key + path: tls.key + - key: ca.crt + path: ca.crt + optional: true + secretName: argocd-repo-server-tls --- apiVersion: apps/v1 kind: Deployment @@ -762,7 +857,7 @@ spec: key: dexserver.disable.tls name: argocd-cmd-params-cm optional: true - image: ghcr.io/dexidp/dex:v2.35.3 + image: ghcr.io/dexidp/dex:v2.38.0 imagePullPolicy: Always name: dex ports: @@ -787,7 +882,7 @@ spec: name: argocd-dex-server-tls initContainers: - command: - - cp + - /bin/cp - -n - /usr/local/bin/argocd - /shared/argocd-dex @@ -829,6 +924,10 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller spec: selector: @@ -842,8 +941,33 @@ spec: app.kubernetes.io/name: argocd-notifications-controller spec: containers: - - command: - - argocd-notifications + - args: + - /usr/local/bin/argocd-notifications + env: + - name: ARGOCD_NOTIFICATIONS_CONTROLLER_LOGFORMAT + valueFrom: + configMapKeyRef: + key: notificationscontroller.log.format + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_NOTIFICATIONS_CONTROLLER_LOGLEVEL + valueFrom: + configMapKeyRef: + key: notificationscontroller.log.level + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_NAMESPACES + valueFrom: + configMapKeyRef: + 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: @@ -921,7 +1045,7 @@ spec: - "" - --appendonly - "no" - image: redis:7.0.7-alpine + image: redis:7.0.14-alpine imagePullPolicy: Always name: redis ports: @@ -931,6 +1055,7 @@ spec: capabilities: drop: - ALL + readOnlyRootFilesystem: true securityContext: runAsNonRoot: true runAsUser: 999 @@ -972,10 +1097,8 @@ spec: weight: 5 automountServiceAccountToken: false containers: - - command: - - sh - - -c - - entrypoint.sh argocd-repo-server --redis argocd-redis:6379 + - args: + - /usr/local/bin/argocd-repo-server env: - name: ARGOCD_RECONCILIATION_TIMEOUT valueFrom: @@ -1001,6 +1124,18 @@ spec: key: reposerver.parallelism.limit name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: reposerver.listen.address + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_LISTEN_METRICS_ADDRESS + valueFrom: + configMapKeyRef: + key: reposerver.metrics.listen.address + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_REPO_SERVER_DISABLE_TLS valueFrom: configMapKeyRef: @@ -1061,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: @@ -1091,12 +1238,42 @@ spec: key: reposerver.streamed.manifest.max.extracted.size name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE + valueFrom: + configMapKeyRef: + key: reposerver.helm.manifest.max.extracted.size + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE + valueFrom: + configMapKeyRef: + key: reposerver.disable.helm.manifest.max.extracted.size + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REVISION_CACHE_LOCK_TIMEOUT + valueFrom: + configMapKeyRef: + key: reposerver.revision.cache.lock.timeout + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_GIT_MODULES_ENABLED valueFrom: configMapKeyRef: 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 @@ -1151,7 +1328,7 @@ spec: name: plugins initContainers: - command: - - cp + - /bin/cp - -n - /usr/local/bin/argocd - /var/run/argocd/argocd-cmp-server @@ -1235,8 +1412,8 @@ spec: topologyKey: kubernetes.io/hostname weight: 5 containers: - - command: - - argocd-server + - args: + - /usr/local/bin/argocd-server env: - name: ARGOCD_SERVER_INSECURE valueFrom: @@ -1412,12 +1589,36 @@ spec: key: server.http.cookie.maxnumber name: argocd-cmd-params-cm optional: true + - name: ARGOCD_SERVER_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: server.listen.address + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_SERVER_METRICS_LISTEN_ADDRESS + valueFrom: + configMapKeyRef: + key: server.metrics.listen.address + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_SERVER_OTLP_ADDRESS valueFrom: configMapKeyRef: 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: @@ -1430,6 +1631,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: @@ -1539,8 +1758,8 @@ spec: topologyKey: kubernetes.io/hostname weight: 5 containers: - - command: - - argocd-application-controller + - args: + - /usr/local/bin/argocd-application-controller env: - name: ARGOCD_CONTROLLER_REPLICAS value: "1" @@ -1556,6 +1775,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: @@ -1658,12 +1889,54 @@ 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: key: application.namespaces name: argocd-cmd-params-cm optional: true + - name: ARGOCD_CONTROLLER_SHARDING_ALGORITHM + valueFrom: + configMapKeyRef: + key: controller.sharding.algorithm + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_KUBECTL_PARALLELISM_LIMIT + valueFrom: + configMapKeyRef: + 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 @@ -1770,6 +2043,10 @@ spec: apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: + labels: + app.kubernetes.io/component: notifications-controller + app.kubernetes.io/name: argocd-notifications-controller + app.kubernetes.io/part-of: argocd name: argocd-notifications-controller-network-policy spec: ingress: @@ -1832,6 +2109,9 @@ spec: - podSelector: matchLabels: app.kubernetes.io/name: argocd-notifications-controller + - podSelector: + matchLabels: + app.kubernetes.io/name: argocd-applicationset-controller ports: - port: 8081 protocol: TCP diff --git a/mkdocs.yml b/mkdocs.yml index ec626be23bb1c..a7e8f86e216cc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -8,10 +8,12 @@ extra_javascript: - assets/versions.js markdown_extensions: - markdown_include.include -- codehilite +- codehilite: + css_class: highlight - admonition - toc: permalink: true +- pymdownx.superfences nav: - Overview: index.md - understand_the_basics.md @@ -21,9 +23,13 @@ nav: - operator-manual/index.md - operator-manual/architecture.md - operator-manual/installation.md + - operator-manual/core.md - operator-manual/declarative-setup.md - operator-manual/app-any-namespace.md - operator-manual/ingress.md + - High Availability: + - Overview: operator-manual/high_availability.md + - Dynamic Cluster Distribution: operator-manual/dynamic-cluster-distribution.md - User Management: - operator-manual/user-management/index.md - operator-manual/user-management/auth0.md @@ -33,6 +39,8 @@ nav: - operator-manual/user-management/keycloak.md - 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 @@ -41,18 +49,19 @@ nav: - operator-manual/tls.md - operator-manual/cluster-bootstrapping.md - operator-manual/secret-management.md - - operator-manual/high_availability.md - operator-manual/disaster_recovery.md + - operator-manual/reconcile.md - operator-manual/webhook.md - operator-manual/health.md - operator-manual/resource_actions.md - operator-manual/custom_tools.md - operator-manual/custom-styles.md + - operator-manual/ui-customization.md - operator-manual/metrics.md - operator-manual/web_based_terminal.md - operator-manual/config-management-plugins.md - operator-manual/deep_links.md - - Notification: + - Notifications: - Overview: operator-manual/notifications/index.md - operator-manual/notifications/triggers.md - operator-manual/notifications/templates.md @@ -65,6 +74,7 @@ nav: - operator-manual/notifications/troubleshooting-errors.md - Notification Services: - operator-manual/notifications/services/alertmanager.md + - operator-manual/notifications/services/awssqs.md - operator-manual/notifications/services/email.md - operator-manual/notifications/services/github.md - operator-manual/notifications/services/googlechat.md @@ -74,6 +84,7 @@ nav: - operator-manual/notifications/services/opsgenie.md - operator-manual/notifications/services/overview.md - operator-manual/notifications/services/pagerduty.md + - operator-manual/notifications/services/pagerduty_v2.md - operator-manual/notifications/services/pushover.md - operator-manual/notifications/services/rocketchat.md - operator-manual/notifications/services/slack.md @@ -98,12 +109,17 @@ nav: - operator-manual/applicationset/Generators-SCM-Provider.md - operator-manual/applicationset/Generators-Cluster-Decision-Resource.md - operator-manual/applicationset/Generators-Pull-Request.md + - operator-manual/applicationset/Generators-Post-Selector.md + - operator-manual/applicationset/Generators-Plugin.md - Template fields: - operator-manual/applicationset/Template.md - operator-manual/applicationset/GoTemplate.md - Controlling Resource Modification: operator-manual/applicationset/Controlling-Resource-Modification.md - Application Pruning & Resource Deletion: operator-manual/applicationset/Application-Deletion.md - - Progressive Rollouts: operator-manual/applicationset/Progressive-Rollouts.md + - Progressive Syncs: operator-manual/applicationset/Progressive-Syncs.md + - Git File Generator Globbing: operator-manual/applicationset/Generators-Git-File-Globbing.md + - ApplicationSet Specification Reference: operator-manual/applicationset/applicationset-specification.md + - ApplicationSet in any namespace: operator-manual/applicationset/Appset-Any-Namespace.md - Server Configuration Parameters: - operator-manual/server-commands/argocd-server.md - operator-manual/server-commands/argocd-application-controller.md @@ -112,6 +128,12 @@ 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 - operator-manual/upgrading/2.4-2.5.md - operator-manual/upgrading/2.3-2.4.md - operator-manual/upgrading/2.2-2.3.md @@ -126,6 +148,7 @@ nav: - operator-manual/upgrading/1.2-1.3.md - operator-manual/upgrading/1.1-1.2.md - operator-manual/upgrading/1.0-1.1.md + - Project Specification Reference: operator-manual/project-specification.md - User Guide: - user-guide/index.md - user-guide/application_sources.md @@ -140,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 @@ -153,16 +178,24 @@ nav: - user-guide/selective_sync.md - user-guide/sync-waves.md - user-guide/sync_windows.md + - user-guide/sync-kubectl.md + - user-guide/skip_reconcile.md - Generating Applications with ApplicationSet: user-guide/application-set.md - user-guide/ci_automation.md - user-guide/app_deletion.md - user-guide/best_practices.md - user-guide/status-badge.md - user-guide/external-url.md + - user-guide/extra_info.md - Notification subscriptions: user-guide/subscriptions.md + - user-guide/annotations-and-labels.md - Command Reference: user-guide/commands/argocd.md + - Application Specification Reference: user-guide/application-specification.md - Developer Guide: - developer-guide/index.md + - Architecture: + - developer-guide/architecture/authz-authn.md + - developer-guide/architecture/components.md - Code Contribution Guide: developer-guide/code-contributions.md - Toolchain Guide: developer-guide/toolchain-guide.md - developer-guide/contributors-quickstart.md @@ -177,7 +210,9 @@ nav: - developer-guide/releasing.md - developer-guide/site.md - developer-guide/static-code-analysis.md - - developer-guide/ui-extensions.md + - Extensions: + - developer-guide/extensions/ui-extensions.md + - developer-guide/extensions/proxy-extensions.md - developer-guide/faq.md - faq.md - security_considerations.md @@ -196,4 +231,15 @@ theme: logo: assets/logo.png name: material palette: + - media: '(prefers-color-scheme: light)' primary: teal + scheme: default + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - media: '(prefers-color-scheme: dark)' + primary: teal + scheme: slate + toggle: + icon: material/brightness-4 + name: Switch to light mode diff --git a/notification_controller/controller/controller.go b/notification_controller/controller/controller.go index e9f33bdc95b60..7d871af4c44a3 100644 --- a/notification_controller/controller/controller.go +++ b/notification_controller/controller/controller.go @@ -6,18 +6,24 @@ import ( "fmt" "time" + "github.com/argoproj/argo-cd/v2/util/glob" + "github.com/argoproj/argo-cd/v2/util/notification/k8s" 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" + "github.com/argoproj/argo-cd/v2/pkg/apis/application" "github.com/argoproj/notifications-engine/pkg/api" "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" @@ -33,8 +39,8 @@ const ( ) var ( - applications = schema.GroupVersionResource{Group: "argoproj.io", Version: "v1alpha1", Resource: "applications"} - appProjects = schema.GroupVersionResource{Group: "argoproj.io", Version: "v1alpha1", Resource: "appprojects"} + applications = schema.GroupVersionResource{Group: application.Group, Version: "v1alpha1", Resource: application.ApplicationPlural} + appProjects = schema.GroupVersionResource{Group: application.Group, Version: "v1alpha1", Resource: application.AppProjectPlural} ) func newAppProjClient(client dynamic.Interface, namespace string) dynamic.ResourceInterface { @@ -52,17 +58,32 @@ func NewController( client dynamic.Interface, argocdService service.Service, namespace string, + applicationNamespaces []string, appLabelSelector string, registry *controller.MetricsRegistry, secretName string, configMapName string, + selfServiceNotificationEnabled bool, ) *notificationController { - appClient := client.Resource(applications) - appInformer := newInformer(appClient.Namespace(namespace), appLabelSelector) - appProjInformer := newInformer(newAppProjClient(client, 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 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}, "") + 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, @@ -70,19 +91,38 @@ 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, "" - } - 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 } +// Check if app is not in the namespace where the controller is in, and also app is not in one of the applicationNamespaces +func checkAppNotInAdditionalNamespaces(app *unstructured.Unstructured, namespace string, applicationNamespaces []string) bool { + return namespace != app.GetNamespace() && !glob.MatchStringInList(applicationNamespaces, app.GetNamespace(), false) +} + func (c *notificationController) alterDestinations(obj v1.Object, destinations services.Destinations, cfg api.Config) services.Destinations { app, ok := (obj).(*unstructured.Unstructured) if !ok { @@ -96,21 +136,39 @@ func (c *notificationController) alterDestinations(obj v1.Object, destinations s return destinations } -func newInformer(resClient dynamic.ResourceInterface, selector string) cache.SharedIndexInformer { +func newInformer(resClient dynamic.ResourceInterface, controllerNamespace string, applicationNamespaces []string, selector string) cache.SharedIndexInformer { + informer := cache.NewSharedIndexInformer( &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (object runtime.Object, err error) { + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + // We are only interested in apps that exist in namespaces the + // user wants to be enabled. options.LabelSelector = selector - return resClient.List(context.Background(), options) + appList, err := resClient.List(context.TODO(), options) + if err != nil { + return nil, fmt.Errorf("failed to list applications: %w", err) + } + newItems := []unstructured.Unstructured{} + for _, res := range appList.Items { + if controllerNamespace == res.GetNamespace() || glob.MatchStringInList(applicationNamespaces, res.GetNamespace(), false) { + newItems = append(newItems, res) + } + } + appList.Items = newItems + return appList, nil }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { options.LabelSelector = selector - return resClient.Watch(context.Background(), options) + return resClient.Watch(context.TODO(), options) }, }, &unstructured.Unstructured{}, resyncPeriod, - cache.Indexers{}, + cache.Indexers{ + cache.NamespaceIndex: func(obj interface{}) ([]string, error) { + return cache.MetaNamespaceIndexFunc(obj) + }, + }, ) return informer } @@ -125,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 new file mode 100644 index 0000000000000..4eedb28f5e001 --- /dev/null +++ b/notification_controller/controller/controller_test.go @@ -0,0 +1,197 @@ +package controller + +import ( + "context" + "testing" + "time" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/sirupsen/logrus/hooks/test" + "github.com/stretchr/testify/assert" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/dynamic/fake" + k8sfake "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/tools/cache" +) + +func TestIsAppSyncStatusRefreshed(t *testing.T) { + logger, _ := test.NewNullLogger() + logEntry := logger.WithField("", "") + + tests := []struct { + name string + app *unstructured.Unstructured + expectedValue bool + }{ + { + name: "No OperationState", + app: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "status": map[string]interface{}{}, + }, + }, + expectedValue: true, + }, + { + name: "No FinishedAt, Completed Phase", + app: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "status": map[string]interface{}{ + "operationState": map[string]interface{}{ + "phase": "Succeeded", + }, + }, + }, + }, + expectedValue: false, + }, + { + name: "FinishedAt After ReconciledAt & ObservedAt", + app: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "status": map[string]interface{}{ + "operationState": map[string]interface{}{ + "finishedAt": "2021-01-01T01:05:00Z", + "phase": "Succeeded", + }, + "reconciledAt": "2021-01-01T01:02:00Z", + "observedAt": "2021-01-01T01:04:00Z", + }, + }, + }, + expectedValue: false, + }, + { + name: "FinishedAt Before ReconciledAt & ObservedAt", + app: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "status": map[string]interface{}{ + "operationState": map[string]interface{}{ + "finishedAt": "2021-01-01T01:02:00Z", + "phase": "Succeeded", + }, + "reconciledAt": "2021-01-01T01:04:00Z", + "observedAt": "2021-01-01T01:06:00Z", + }, + }, + }, + expectedValue: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actualValue := isAppSyncStatusRefreshed(test.app, logEntry) + assert.Equal(t, test.expectedValue, actualValue) + }) + } +} + +func TestGetAppProj_invalidProjectNestedString(t *testing.T) { + app := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "spec": map[string]interface{}{}, + }, + } + informer := cache.NewSharedIndexInformer(nil, nil, 0, nil) + proj := getAppProj(app, informer) + + assert.Nil(t, proj) +} + +func TestInit(t *testing.T) { + scheme := runtime.NewScheme() + err := v1alpha1.SchemeBuilder.AddToScheme(scheme) + if err != nil { + t.Fatalf("Error registering the resource: %v", err) + } + dynamicClient := fake.NewSimpleDynamicClient(scheme) + k8sClient := k8sfake.NewSimpleClientset() + appLabelSelector := "app=test" + + 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) { + scheme := runtime.NewScheme() + err := v1alpha1.SchemeBuilder.AddToScheme(scheme) + if err != nil { + t.Fatalf("Error registering the resource: %v", err) + } + dynamicClient := fake.NewSimpleDynamicClient(scheme) + k8sClient := k8sfake.NewSimpleClientset() + appLabelSelector := "app=test" + + nc := NewController( + k8sClient, + dynamicClient, + nil, + "default", + []string{}, + appLabelSelector, + nil, + "my-secret", + "my-configmap", + false, + ) + + assert.NotNil(t, nc) + + // Use a short timeout to simulate a timeout during cache synchronization + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond) + defer cancel() + + err = nc.Init(ctx) + + // Expect an error & add assertion for the error message + assert.Error(t, err) + assert.Equal(t, "Timed out waiting for caches to sync", err.Error()) +} + +func TestCheckAppNotInAdditionalNamespaces(t *testing.T) { + app := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "spec": map[string]interface{}{}, + }, + } + namespace := "argocd" + var applicationNamespaces []string + applicationNamespaces = append(applicationNamespaces, "namespace1") + applicationNamespaces = append(applicationNamespaces, "namespace2") + + // app is in same namespace as controller's namespace + app.SetNamespace(namespace) + assert.False(t, checkAppNotInAdditionalNamespaces(app, namespace, applicationNamespaces)) + + // app is not in the namespace as controller's namespace, but it is in one of the applicationNamespaces + app.SetNamespace("namespace2") + assert.False(t, checkAppNotInAdditionalNamespaces(app, "", applicationNamespaces)) + + // app is not in the namespace as controller's namespace, and it is not in any of the applicationNamespaces + app.SetNamespace("namespace3") + assert.True(t, checkAppNotInAdditionalNamespaces(app, "", applicationNamespaces)) +} diff --git a/notifications_catalog/install.yaml b/notifications_catalog/install.yaml index d399dcf7a3fbd..7457b25ddad89 100644 --- a/notifications_catalog/install.yaml +++ b/notifications_catalog/install.yaml @@ -40,8 +40,7 @@ data: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -68,8 +67,7 @@ data: "value": "{{.app.status.sync.revision}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" @@ -119,8 +117,7 @@ data: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -143,8 +140,7 @@ data: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" @@ -194,8 +190,7 @@ data: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -222,8 +217,7 @@ data: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" @@ -273,8 +267,7 @@ data: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -301,8 +294,7 @@ data: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" @@ -356,8 +348,7 @@ data: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -380,8 +371,7 @@ data: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" @@ -430,8 +420,7 @@ data: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -458,8 +447,7 @@ data: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" @@ -499,11 +487,11 @@ data: when: app.metadata.deletionTimestamp != nil trigger.on-deployed: | - description: Application is synced and healthy. Triggered once per commit. - oncePer: app.status.operationState.syncResult.revision + oncePer: app.status.operationState?.syncResult?.revision send: - app-deployed - when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status - == 'Healthy' + when: app.status.operationState != nil and app.status.operationState.phase in ['Succeeded'] + and app.status.health.status == 'Healthy' trigger.on-health-degraded: | - description: Application has degraded send: @@ -513,12 +501,13 @@ data: - description: Application syncing has failed send: - app-sync-failed - when: app.status.operationState.phase in ['Error', 'Failed'] + when: app.status.operationState != nil and app.status.operationState.phase in ['Error', + 'Failed'] trigger.on-sync-running: | - description: Application is being synced send: - app-sync-running - when: app.status.operationState.phase in ['Running'] + when: app.status.operationState != nil and app.status.operationState.phase in ['Running'] trigger.on-sync-status-unknown: | - description: Application status is 'Unknown' send: @@ -528,7 +517,7 @@ data: - description: Application syncing has succeeded send: - app-sync-succeeded - when: app.status.operationState.phase in ['Succeeded'] + when: app.status.operationState != nil and app.status.operationState.phase in ['Succeeded'] kind: ConfigMap metadata: creationTimestamp: null diff --git a/notifications_catalog/templates/app-deployed.yaml b/notifications_catalog/templates/app-deployed.yaml index 843bf57e21a89..ee58c775f1fd8 100644 --- a/notifications_catalog/templates/app-deployed.yaml +++ b/notifications_catalog/templates/app-deployed.yaml @@ -25,8 +25,7 @@ slack: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -52,8 +51,7 @@ teams: "value": "{{.app.status.sync.revision}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" diff --git a/notifications_catalog/templates/app-health-degraded.yaml b/notifications_catalog/templates/app-health-degraded.yaml index 46c39b2e9ca0c..59115c9a14935 100644 --- a/notifications_catalog/templates/app-health-degraded.yaml +++ b/notifications_catalog/templates/app-health-degraded.yaml @@ -21,8 +21,7 @@ slack: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -44,8 +43,7 @@ teams: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" diff --git a/notifications_catalog/templates/app-sync-failed.yaml b/notifications_catalog/templates/app-sync-failed.yaml index 4a5ece85ba541..a4c23787dde8b 100644 --- a/notifications_catalog/templates/app-sync-failed.yaml +++ b/notifications_catalog/templates/app-sync-failed.yaml @@ -21,8 +21,7 @@ slack: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -48,8 +47,7 @@ teams: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" diff --git a/notifications_catalog/templates/app-sync-running.yaml b/notifications_catalog/templates/app-sync-running.yaml index b2a86042e3ce2..434132ad86d89 100644 --- a/notifications_catalog/templates/app-sync-running.yaml +++ b/notifications_catalog/templates/app-sync-running.yaml @@ -21,8 +21,7 @@ slack: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -47,8 +46,7 @@ teams: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" diff --git a/notifications_catalog/templates/app-sync-status-unknown.yaml b/notifications_catalog/templates/app-sync-status-unknown.yaml index b1af244fb6d2d..c893070bfcc63 100644 --- a/notifications_catalog/templates/app-sync-status-unknown.yaml +++ b/notifications_catalog/templates/app-sync-status-unknown.yaml @@ -26,8 +26,7 @@ slack: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -48,8 +47,7 @@ teams: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" diff --git a/notifications_catalog/templates/app-sync-succeeded.yaml b/notifications_catalog/templates/app-sync-succeeded.yaml index d791de55149a4..76e467bd1c37d 100644 --- a/notifications_catalog/templates/app-sync-succeeded.yaml +++ b/notifications_catalog/templates/app-sync-succeeded.yaml @@ -21,8 +21,7 @@ slack: "short": true } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "title": "{{$c.type}}", "value": "{{$c.message}}", @@ -48,8 +47,7 @@ teams: "value": "{{.app.spec.source.repoURL}}" } {{range $index, $c := .app.status.conditions}} - {{if not $index}},{{end}} - {{if $index}},{{end}} + , { "name": "{{$c.type}}", "value": "{{$c.message}}" diff --git a/notifications_catalog/triggers/on-deployed.yaml b/notifications_catalog/triggers/on-deployed.yaml index 93fdb0ab8666a..486fb15bd94d8 100644 --- a/notifications_catalog/triggers/on-deployed.yaml +++ b/notifications_catalog/triggers/on-deployed.yaml @@ -1,4 +1,4 @@ -- when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy' +- when: app.status.operationState != nil and app.status.operationState.phase in ['Succeeded'] and app.status.health.status == 'Healthy' description: Application is synced and healthy. Triggered once per commit. send: [app-deployed] - oncePer: app.status.operationState.syncResult.revision \ No newline at end of file + oncePer: app.status.operationState?.syncResult?.revision diff --git a/notifications_catalog/triggers/on-sync-failed.yaml b/notifications_catalog/triggers/on-sync-failed.yaml index 888a007f39247..b19afc561b0d5 100644 --- a/notifications_catalog/triggers/on-sync-failed.yaml +++ b/notifications_catalog/triggers/on-sync-failed.yaml @@ -1,3 +1,3 @@ -- when: app.status.operationState.phase in ['Error', 'Failed'] +- when: app.status.operationState != nil and app.status.operationState.phase in ['Error', 'Failed'] description: Application syncing has failed send: [app-sync-failed] diff --git a/notifications_catalog/triggers/on-sync-running.yaml b/notifications_catalog/triggers/on-sync-running.yaml index 005d06177051e..8ed62c9bf9fe5 100644 --- a/notifications_catalog/triggers/on-sync-running.yaml +++ b/notifications_catalog/triggers/on-sync-running.yaml @@ -1,3 +1,3 @@ -- when: app.status.operationState.phase in ['Running'] +- when: app.status.operationState != nil and app.status.operationState.phase in ['Running'] description: Application is being synced send: [app-sync-running] diff --git a/notifications_catalog/triggers/on-sync-succeeded.yaml b/notifications_catalog/triggers/on-sync-succeeded.yaml index 9e1c9fef5af3b..c3eb0e1aead70 100644 --- a/notifications_catalog/triggers/on-sync-succeeded.yaml +++ b/notifications_catalog/triggers/on-sync-succeeded.yaml @@ -1,3 +1,3 @@ -- when: app.status.operationState.phase in ['Succeeded'] +- when: app.status.operationState != nil and app.status.operationState.phase in ['Succeeded'] description: Application syncing has succeeded send: [app-sync-succeeded] diff --git a/pkg/apiclient/apiclient.go b/pkg/apiclient/apiclient.go index 5f122433ee285..83e841dd99bea 100644 --- a/pkg/apiclient/apiclient.go +++ b/pkg/apiclient/apiclient.go @@ -22,7 +22,6 @@ import ( grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry" "github.com/hashicorp/go-retryablehttp" log "github.com/sirupsen/logrus" - "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "golang.org/x/oauth2" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -46,7 +45,6 @@ import ( settingspkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/settings" versionpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/version" "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/util/argo" "github.com/argoproj/argo-cd/v2/util/env" grpc_util "github.com/argoproj/argo-cd/v2/util/grpc" @@ -104,7 +102,7 @@ type Client interface { NewProjectClientOrDie() (io.Closer, projectpkg.ProjectServiceClient) NewAccountClient() (io.Closer, accountpkg.AccountServiceClient, error) NewAccountClientOrDie() (io.Closer, accountpkg.AccountServiceClient) - WatchApplicationWithRetry(ctx context.Context, appName string, revision string) chan *argoappv1.ApplicationWatchEvent + WatchApplicationWithRetry(ctx context.Context, appName string, revision string) chan *v1alpha1.ApplicationWatchEvent } // ClientOptions hold address, security, and other settings for the API client. @@ -127,6 +125,11 @@ type ClientOptions struct { Headers []string HttpRetryMax int KubeOverrides *clientcmd.ConfigOverrides + AppControllerName string + ServerName string + RedisHaProxyName string + RedisName string + RepoServerName string } type client struct { @@ -203,14 +206,13 @@ func NewClient(opts *ClientOptions) (Client, error) { c.UserAgent = fmt.Sprintf("%s/%s", common.ArgoCDUserAgentName, common.GetVersion().Version) } // Override server address if specified in env or CLI flag - if serverFromEnv := os.Getenv(EnvArgoCDServer); serverFromEnv != "" { - c.ServerAddr = serverFromEnv - } + c.ServerAddr = env.StringFromEnv(EnvArgoCDServer, c.ServerAddr) if opts.PortForward || opts.PortForwardNamespace != "" { if opts.KubeOverrides == nil { opts.KubeOverrides = &clientcmd.ConfigOverrides{} } - port, err := kube.PortForward(8080, opts.PortForwardNamespace, opts.KubeOverrides, "app.kubernetes.io/name=argocd-server") + serverPodLabelSelector := common.LabelKeyAppName + "=" + opts.ServerName + port, err := kube.PortForward(8080, opts.PortForwardNamespace, opts.KubeOverrides, serverPodLabelSelector) if err != nil { return nil, err } @@ -224,14 +226,8 @@ func NewClient(opts *ClientOptions) (Client, error) { if c.ServerAddr == "" { return nil, errors.New("Argo CD server address unspecified") } - if parts := strings.Split(c.ServerAddr, ":"); len(parts) == 1 { - // If port is unspecified, assume the most likely port - c.ServerAddr += ":443" - } // Override auth-token if specified in env variable or CLI flag - if authFromEnv := os.Getenv(EnvArgoCDAuthToken); authFromEnv != "" { - c.AuthToken = authFromEnv - } + c.AuthToken = env.StringFromEnv(EnvArgoCDAuthToken, c.AuthToken) if opts.AuthToken != "" { c.AuthToken = strings.TrimSpace(opts.AuthToken) } @@ -285,8 +281,12 @@ func NewClient(opts *ClientOptions) (Client, error) { } } if !c.GRPCWeb { - //test if we need to set it to true - //if a call to grpc failed, then try again with GRPCWeb + if parts := strings.Split(c.ServerAddr, ":"); len(parts) == 1 { + // If port is unspecified, assume the most likely port + c.ServerAddr += ":443" + } + // test if we need to set it to true + // if a call to grpc failed, then try again with GRPCWeb conn, versionIf, err := c.NewVersionClient() if err == nil { defer argoio.Close(conn) @@ -524,8 +524,8 @@ func (c *client) newConn() (*grpc.ClientConn, io.Closer, error) { dialOpts = append(dialOpts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(MaxGRPCMessageSize), grpc.MaxCallSendMsgSize(MaxGRPCMessageSize))) dialOpts = append(dialOpts, grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor(retryOpts...))) dialOpts = append(dialOpts, grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(grpc_retry.UnaryClientInterceptor(retryOpts...)))) - dialOpts = append(dialOpts, grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor())) - dialOpts = append(dialOpts, grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor())) + dialOpts = append(dialOpts, grpc.WithUnaryInterceptor(grpc_util.OTELUnaryClientInterceptor())) + dialOpts = append(dialOpts, grpc.WithStreamInterceptor(grpc_util.OTELStreamClientInterceptor())) ctx := context.Background() @@ -806,10 +806,10 @@ func (c *client) NewAccountClientOrDie() (io.Closer, accountpkg.AccountServiceCl // WatchApplicationWithRetry returns a channel of watch events for an application, retrying the // watch upon errors. Closes the returned channel when the context is cancelled. -func (c *client) WatchApplicationWithRetry(ctx context.Context, appName string, revision string) chan *argoappv1.ApplicationWatchEvent { - appEventsCh := make(chan *argoappv1.ApplicationWatchEvent) +func (c *client) WatchApplicationWithRetry(ctx context.Context, appName string, revision string) chan *v1alpha1.ApplicationWatchEvent { + appEventsCh := make(chan *v1alpha1.ApplicationWatchEvent) cancelled := false - appName, appNs := argo.ParseAppQualifiedName(appName, "") + appName, appNs := argo.ParseFromQualifiedName(appName, "") go func() { defer close(appEventsCh) for !cancelled { diff --git a/pkg/apiclient/apiclient_test.go b/pkg/apiclient/apiclient_test.go index 7bb3b36befdde..b4b35d0b80d48 100644 --- a/pkg/apiclient/apiclient_test.go +++ b/pkg/apiclient/apiclient_test.go @@ -7,10 +7,34 @@ import ( ) func Test_parseHeaders(t *testing.T) { - headerString := []string{"foo:", "foo1:bar1", "foo2:bar2:bar2"} - headers, err := parseHeaders(headerString) - assert.NoError(t, err) - assert.Equal(t, headers.Get("foo"), "") - assert.Equal(t, headers.Get("foo1"), "bar1") - assert.Equal(t, headers.Get("foo2"), "bar2:bar2") + t.Run("Header parsed successfully", func(t *testing.T) { + headerString := []string{"foo:", "foo1:bar1", "foo2:bar2:bar2"} + headers, err := parseHeaders(headerString) + assert.NoError(t, err) + assert.Equal(t, headers.Get("foo"), "") + assert.Equal(t, headers.Get("foo1"), "bar1") + assert.Equal(t, headers.Get("foo2"), "bar2:bar2") + }) + + t.Run("Header parsed error", func(t *testing.T) { + headerString := []string{"foo"} + _, err := parseHeaders(headerString) + assert.ErrorContains(t, err, "additional headers must be colon(:)-separated: foo") + }) +} + +func Test_parseGRPCHeaders(t *testing.T) { + t.Run("Header parsed successfully", func(t *testing.T) { + headerStrings := []string{"origin: https://foo.bar", "content-length: 123"} + headers, err := parseGRPCHeaders(headerStrings) + assert.NoError(t, err) + assert.Equal(t, headers.Get("origin"), []string{" https://foo.bar"}) + assert.Equal(t, headers.Get("content-length"), []string{" 123"}) + }) + + t.Run("Header parsed error", func(t *testing.T) { + headerString := []string{"foo"} + _, err := parseGRPCHeaders(headerString) + assert.ErrorContains(t, err, "additional headers must be colon(:)-separated: foo") + }) } diff --git a/pkg/apiclient/application/application.pb.go b/pkg/apiclient/application/application.pb.go index 0de79ae034d70..70c63c36bc333 100644 --- a/pkg/apiclient/application/application.pb.go +++ b/pkg/apiclient/application/application.pb.go @@ -36,11 +36,15 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// ApplicationQuery is a query for application resources +// ApplicationQuery is a query for application resources. When getting multiple applications, the "projects" field acts +// as a filter. When getting a single application, you may specify either zero or one project. If you specify zero +// projects, the application will be returned regardless of which project it belongs to (assuming you have access). If +// you specify one project, the application will only be returned if it exists and belongs to the specified project. +// Otherwise you will receive a 404. 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"` @@ -51,7 +55,9 @@ type ApplicationQuery struct { // the repoURL to restrict returned list applications Repo *string `protobuf:"bytes,6,opt,name=repo" json:"repo,omitempty"` // the application's namespace - AppNamespace *string `protobuf:"bytes,7,opt,name=appNamespace" json:"appNamespace,omitempty"` + AppNamespace *string `protobuf:"bytes,7,opt,name=appNamespace" json:"appNamespace,omitempty"` + // the project names to restrict returned list applications (legacy name for backwards-compatibility) + Project []string `protobuf:"bytes,8,rep,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -139,6 +145,13 @@ func (m *ApplicationQuery) GetAppNamespace() string { return "" } +func (m *ApplicationQuery) GetProject() []string { + if m != nil { + return m.Project + } + return nil +} + type NodeQuery struct { // the application's name Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` @@ -202,6 +215,7 @@ type RevisionMetadataQuery struct { Revision *string `protobuf:"bytes,2,req,name=revision" json:"revision,omitempty"` // the application's namespace AppNamespace *string `protobuf:"bytes,3,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,4,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -261,6 +275,13 @@ func (m *RevisionMetadataQuery) GetAppNamespace() string { return "" } +func (m *RevisionMetadataQuery) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + // ApplicationEventsQuery is a query for application resource events type ApplicationResourceEventsQuery struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` @@ -268,6 +289,7 @@ type ApplicationResourceEventsQuery struct { ResourceName *string `protobuf:"bytes,3,opt,name=resourceName" json:"resourceName,omitempty"` ResourceUID *string `protobuf:"bytes,4,opt,name=resourceUID" json:"resourceUID,omitempty"` AppNamespace *string `protobuf:"bytes,5,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,6,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -341,11 +363,19 @@ func (m *ApplicationResourceEventsQuery) GetAppNamespace() string { return "" } +func (m *ApplicationResourceEventsQuery) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + // ManifestQuery is a query for manifest resources type ApplicationManifestQuery struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` Revision *string `protobuf:"bytes,2,opt,name=revision" json:"revision,omitempty"` AppNamespace *string `protobuf:"bytes,3,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,4,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -405,6 +435,13 @@ func (m *ApplicationManifestQuery) GetAppNamespace() string { return "" } +func (m *ApplicationManifestQuery) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type FileChunk struct { Chunk []byte `protobuf:"bytes,1,req,name=chunk" json:"chunk,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -456,6 +493,7 @@ type ApplicationManifestQueryWithFiles struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` Checksum *string `protobuf:"bytes,2,req,name=checksum" json:"checksum,omitempty"` AppNamespace *string `protobuf:"bytes,3,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,4,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -515,6 +553,13 @@ func (m *ApplicationManifestQueryWithFiles) GetAppNamespace() string { return "" } +func (m *ApplicationManifestQueryWithFiles) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type ApplicationManifestQueryWithFilesWrapper struct { // Types that are valid to be assigned to Part: // *ApplicationManifestQueryWithFilesWrapper_Query @@ -712,6 +757,7 @@ func (m *ApplicationCreateRequest) GetValidate() bool { type ApplicationUpdateRequest struct { Application *v1alpha1.Application `protobuf:"bytes,1,req,name=application" json:"application,omitempty"` Validate *bool `protobuf:"varint,2,opt,name=validate" json:"validate,omitempty"` + Project *string `protobuf:"bytes,3,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -764,11 +810,19 @@ func (m *ApplicationUpdateRequest) GetValidate() bool { return false } +func (m *ApplicationUpdateRequest) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type ApplicationDeleteRequest struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` Cascade *bool `protobuf:"varint,2,opt,name=cascade" json:"cascade,omitempty"` PropagationPolicy *string `protobuf:"bytes,3,opt,name=propagationPolicy" json:"propagationPolicy,omitempty"` AppNamespace *string `protobuf:"bytes,4,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,5,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -835,6 +889,13 @@ func (m *ApplicationDeleteRequest) GetAppNamespace() string { return "" } +func (m *ApplicationDeleteRequest) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type SyncOptions struct { Items []string `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -895,6 +956,7 @@ type ApplicationSyncRequest struct { RetryStrategy *v1alpha1.RetryStrategy `protobuf:"bytes,10,opt,name=retryStrategy" json:"retryStrategy,omitempty"` SyncOptions *SyncOptions `protobuf:"bytes,11,opt,name=syncOptions" json:"syncOptions,omitempty"` AppNamespace *string `protobuf:"bytes,12,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,13,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1010,12 +1072,20 @@ func (m *ApplicationSyncRequest) GetAppNamespace() string { return "" } +func (m *ApplicationSyncRequest) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + // ApplicationUpdateSpecRequest is a request to update application spec type ApplicationUpdateSpecRequest struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` Spec *v1alpha1.ApplicationSpec `protobuf:"bytes,2,req,name=spec" json:"spec,omitempty"` Validate *bool `protobuf:"varint,3,opt,name=validate" json:"validate,omitempty"` AppNamespace *string `protobuf:"bytes,4,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,5,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1082,12 +1152,20 @@ func (m *ApplicationUpdateSpecRequest) GetAppNamespace() string { return "" } +func (m *ApplicationUpdateSpecRequest) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + // ApplicationPatchRequest is a request to patch an application type ApplicationPatchRequest struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` Patch *string `protobuf:"bytes,2,req,name=patch" json:"patch,omitempty"` PatchType *string `protobuf:"bytes,3,req,name=patchType" json:"patchType,omitempty"` AppNamespace *string `protobuf:"bytes,5,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,6,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1154,12 +1232,20 @@ func (m *ApplicationPatchRequest) GetAppNamespace() string { return "" } +func (m *ApplicationPatchRequest) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type ApplicationRollbackRequest struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` Id *int64 `protobuf:"varint,2,req,name=id" json:"id,omitempty"` DryRun *bool `protobuf:"varint,3,opt,name=dryRun" json:"dryRun,omitempty"` Prune *bool `protobuf:"varint,4,opt,name=prune" json:"prune,omitempty"` AppNamespace *string `protobuf:"bytes,6,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,7,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1233,6 +1319,13 @@ func (m *ApplicationRollbackRequest) GetAppNamespace() string { return "" } +func (m *ApplicationRollbackRequest) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type ApplicationResourceRequest struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` Namespace *string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"` @@ -1241,6 +1334,7 @@ type ApplicationResourceRequest struct { Group *string `protobuf:"bytes,5,opt,name=group" json:"group,omitempty"` Kind *string `protobuf:"bytes,6,req,name=kind" json:"kind,omitempty"` AppNamespace *string `protobuf:"bytes,7,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,8,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1328,6 +1422,13 @@ func (m *ApplicationResourceRequest) GetAppNamespace() string { return "" } +func (m *ApplicationResourceRequest) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type ApplicationResourcePatchRequest struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` Namespace *string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"` @@ -1338,6 +1439,7 @@ type ApplicationResourcePatchRequest struct { Patch *string `protobuf:"bytes,7,req,name=patch" json:"patch,omitempty"` PatchType *string `protobuf:"bytes,8,req,name=patchType" json:"patchType,omitempty"` AppNamespace *string `protobuf:"bytes,9,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,10,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1439,6 +1541,13 @@ func (m *ApplicationResourcePatchRequest) GetAppNamespace() string { return "" } +func (m *ApplicationResourcePatchRequest) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type ApplicationResourceDeleteRequest struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` Namespace *string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"` @@ -1449,6 +1558,7 @@ type ApplicationResourceDeleteRequest struct { Force *bool `protobuf:"varint,7,opt,name=force" json:"force,omitempty"` Orphan *bool `protobuf:"varint,8,opt,name=orphan" json:"orphan,omitempty"` AppNamespace *string `protobuf:"bytes,9,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,10,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1550,6 +1660,13 @@ func (m *ApplicationResourceDeleteRequest) GetAppNamespace() string { return "" } +func (m *ApplicationResourceDeleteRequest) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type ResourceActionRunRequest struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` Namespace *string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"` @@ -1559,6 +1676,7 @@ type ResourceActionRunRequest struct { Kind *string `protobuf:"bytes,6,req,name=kind" json:"kind,omitempty"` Action *string `protobuf:"bytes,7,req,name=action" json:"action,omitempty"` AppNamespace *string `protobuf:"bytes,8,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,9,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1653,6 +1771,13 @@ func (m *ResourceActionRunRequest) GetAppNamespace() string { return "" } +func (m *ResourceActionRunRequest) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type ResourceActionsListResponse struct { Actions []*v1alpha1.ResourceAction `protobuf:"bytes,1,rep,name=actions" json:"actions,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -1763,6 +1888,7 @@ type ApplicationPodLogsQuery struct { ResourceName *string `protobuf:"bytes,13,opt,name=resourceName" json:"resourceName,omitempty"` Previous *bool `protobuf:"varint,14,opt,name=previous" json:"previous,omitempty"` AppNamespace *string `protobuf:"bytes,15,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,16,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1906,6 +2032,13 @@ func (m *ApplicationPodLogsQuery) GetAppNamespace() string { return "" } +func (m *ApplicationPodLogsQuery) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type LogEntry struct { Content *string `protobuf:"bytes,1,req,name=content" json:"content,omitempty"` // deprecated in favor of timeStampStr since meta.v1.Time don't support nano time @@ -1989,6 +2122,7 @@ func (m *LogEntry) GetPodName() string { type OperationTerminateRequest struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` AppNamespace *string `protobuf:"bytes,2,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,3,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2041,9 +2175,17 @@ func (m *OperationTerminateRequest) GetAppNamespace() string { return "" } +func (m *OperationTerminateRequest) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type ApplicationSyncWindowsQuery struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` AppNamespace *string `protobuf:"bytes,2,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,3,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2096,6 +2238,13 @@ func (m *ApplicationSyncWindowsQuery) GetAppNamespace() string { return "" } +func (m *ApplicationSyncWindowsQuery) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type ApplicationSyncWindowsResponse struct { ActiveWindows []*ApplicationSyncWindow `protobuf:"bytes,1,rep,name=activeWindows" json:"activeWindows,omitempty"` AssignedWindows []*ApplicationSyncWindow `protobuf:"bytes,2,rep,name=assignedWindows" json:"assignedWindows,omitempty"` @@ -2277,6 +2426,7 @@ type ResourcesQuery struct { Group *string `protobuf:"bytes,5,opt,name=group" json:"group,omitempty"` Kind *string `protobuf:"bytes,6,opt,name=kind" json:"kind,omitempty"` AppNamespace *string `protobuf:"bytes,7,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,8,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2364,6 +2514,13 @@ func (m *ResourcesQuery) GetAppNamespace() string { return "" } +func (m *ResourcesQuery) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + type ManagedResourcesResponse struct { Items []*v1alpha1.ResourceDiff `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -2532,6 +2689,7 @@ func (m *LinksResponse) GetItems() []*LinkInfo { type ListAppLinksRequest struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` Namespace *string `protobuf:"bytes,3,opt,name=namespace" json:"namespace,omitempty"` + Project *string `protobuf:"bytes,4,opt,name=project" json:"project,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2584,6 +2742,13 @@ func (m *ListAppLinksRequest) GetNamespace() string { return "" } +func (m *ListAppLinksRequest) GetProject() string { + if m != nil && m.Project != nil { + return *m.Project + } + return "" +} + func init() { proto.RegisterType((*ApplicationQuery)(nil), "application.ApplicationQuery") proto.RegisterType((*NodeQuery)(nil), "application.NodeQuery") @@ -2627,169 +2792,175 @@ func init() { } var fileDescriptor_df6e82b174b5eaec = []byte{ - // 2581 bytes of a gzipped FileDescriptorProto + // 2673 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0xcd, 0x8f, 0x1c, 0x47, - 0x15, 0xa7, 0x66, 0xbf, 0x66, 0xde, 0xac, 0xbf, 0x2a, 0xf1, 0xd2, 0x69, 0xaf, 0xcd, 0xba, 0xfd, - 0xb5, 0x5e, 0x7b, 0x67, 0xec, 0xc1, 0x20, 0x67, 0x13, 0x04, 0xb6, 0xe3, 0x2f, 0x58, 0x3b, 0xa6, - 0xd7, 0xc6, 0x28, 0x1c, 0xa0, 0xd2, 0x53, 0x3b, 0xdb, 0x6c, 0x4f, 0x77, 0xbb, 0xbb, 0x67, 0xac, - 0x91, 0xf1, 0x25, 0x88, 0x13, 0x51, 0x90, 0x92, 0x1c, 0x50, 0x14, 0x21, 0x94, 0x28, 0x17, 0x2e, - 0xdc, 0x10, 0x12, 0x17, 0xb8, 0x20, 0x90, 0x38, 0x20, 0x3e, 0x2e, 0x39, 0x21, 0x8b, 0x1b, 0x17, - 0xfe, 0x04, 0x54, 0xd5, 0x55, 0xdd, 0xd5, 0x33, 0x3d, 0x3d, 0xbd, 0xec, 0x46, 0xf1, 0xad, 0x5e, - 0x4d, 0xd5, 0x7b, 0xbf, 0x7a, 0xf5, 0xbe, 0xea, 0xf5, 0xc0, 0xc9, 0x90, 0x06, 0x7d, 0x1a, 0x34, - 0x89, 0xef, 0x3b, 0xb6, 0x45, 0x22, 0xdb, 0x73, 0xd5, 0x71, 0xc3, 0x0f, 0xbc, 0xc8, 0xc3, 0x75, - 0x65, 0x4a, 0x5f, 0xec, 0x78, 0x5e, 0xc7, 0xa1, 0x4d, 0xe2, 0xdb, 0x4d, 0xe2, 0xba, 0x5e, 0xc4, - 0xa7, 0xc3, 0x78, 0xa9, 0x6e, 0x6c, 0x5f, 0x0e, 0x1b, 0xb6, 0xc7, 0x7f, 0xb5, 0xbc, 0x80, 0x36, - 0xfb, 0x17, 0x9b, 0x1d, 0xea, 0xd2, 0x80, 0x44, 0xb4, 0x2d, 0xd6, 0x5c, 0x4a, 0xd7, 0x74, 0x89, - 0xb5, 0x65, 0xbb, 0x34, 0x18, 0x34, 0xfd, 0xed, 0x0e, 0x9b, 0x08, 0x9b, 0x5d, 0x1a, 0x91, 0xbc, - 0x5d, 0xeb, 0x1d, 0x3b, 0xda, 0xea, 0xbd, 0xd9, 0xb0, 0xbc, 0x6e, 0x93, 0x04, 0x1d, 0xcf, 0x0f, - 0xbc, 0x1f, 0xf2, 0xc1, 0xaa, 0xd5, 0x6e, 0xf6, 0x5b, 0x29, 0x03, 0xf5, 0x2c, 0xfd, 0x8b, 0xc4, - 0xf1, 0xb7, 0xc8, 0x28, 0xb7, 0xeb, 0x13, 0xb8, 0x05, 0xd4, 0xf7, 0x84, 0x6e, 0xf8, 0xd0, 0x8e, - 0xbc, 0x60, 0xa0, 0x0c, 0x63, 0x36, 0xc6, 0xa7, 0x08, 0x0e, 0x5e, 0x49, 0xe5, 0x7d, 0xbb, 0x47, - 0x83, 0x01, 0xc6, 0x30, 0xed, 0x92, 0x2e, 0xd5, 0xd0, 0x12, 0x5a, 0xae, 0x99, 0x7c, 0x8c, 0x35, - 0x98, 0x0b, 0xe8, 0x66, 0x40, 0xc3, 0x2d, 0xad, 0xc2, 0xa7, 0x25, 0x89, 0x75, 0xa8, 0x32, 0xe1, - 0xd4, 0x8a, 0x42, 0x6d, 0x6a, 0x69, 0x6a, 0xb9, 0x66, 0x26, 0x34, 0x5e, 0x86, 0x03, 0x01, 0x0d, - 0xbd, 0x5e, 0x60, 0xd1, 0xef, 0xd0, 0x20, 0xb4, 0x3d, 0x57, 0x9b, 0xe6, 0xbb, 0x87, 0xa7, 0x19, - 0x97, 0x90, 0x3a, 0xd4, 0x8a, 0xbc, 0x40, 0x9b, 0xe1, 0x4b, 0x12, 0x9a, 0xe1, 0x61, 0xc0, 0xb5, - 0xd9, 0x18, 0x0f, 0x1b, 0x63, 0x03, 0xe6, 0x89, 0xef, 0xdf, 0x25, 0x5d, 0x1a, 0xfa, 0xc4, 0xa2, - 0xda, 0x1c, 0xff, 0x2d, 0x33, 0x67, 0x5c, 0x83, 0xda, 0x5d, 0xaf, 0x4d, 0xc7, 0x1f, 0x6a, 0x98, - 0x49, 0x25, 0x87, 0xc9, 0x36, 0x1c, 0x36, 0x69, 0xdf, 0x66, 0x20, 0xef, 0xd0, 0x88, 0xb4, 0x49, - 0x44, 0x86, 0x19, 0x56, 0x12, 0x86, 0x3a, 0x54, 0x03, 0xb1, 0x58, 0xab, 0xf0, 0xf9, 0x84, 0x1e, - 0x11, 0x36, 0x95, 0x23, 0xec, 0x2f, 0x08, 0x8e, 0x29, 0xd7, 0x61, 0x0a, 0x25, 0x5d, 0xef, 0x53, - 0x37, 0x0a, 0xc7, 0x8b, 0x3d, 0x0f, 0x87, 0xa4, 0x3e, 0x87, 0x0f, 0x33, 0xfa, 0x03, 0x03, 0xa2, - 0x4e, 0x4a, 0x20, 0xea, 0x1c, 0x5e, 0x82, 0xba, 0xa4, 0x1f, 0xdc, 0x7e, 0x4d, 0x5c, 0x9a, 0x3a, - 0x35, 0x72, 0x9c, 0x99, 0x9c, 0xe3, 0xb8, 0xa0, 0x29, 0xa7, 0xb9, 0x43, 0x5c, 0x7b, 0x93, 0x86, - 0x51, 0x59, 0xf5, 0xa1, 0x1d, 0xab, 0xef, 0x38, 0xd4, 0x6e, 0xd8, 0x0e, 0xbd, 0xb6, 0xd5, 0x73, - 0xb7, 0xf1, 0x8b, 0x30, 0x63, 0xb1, 0x01, 0x97, 0x30, 0x6f, 0xc6, 0x84, 0xf1, 0x18, 0x8e, 0x8f, - 0x83, 0xf4, 0xd0, 0x8e, 0xb6, 0xd8, 0xf6, 0x70, 0x1c, 0x36, 0x6b, 0x8b, 0x5a, 0xdb, 0x61, 0xaf, - 0x2b, 0xaf, 0x56, 0xd2, 0xa5, 0xb0, 0xfd, 0x0a, 0xc1, 0xf2, 0x44, 0xc9, 0x0f, 0x03, 0xe2, 0xfb, - 0x34, 0xc0, 0x37, 0x60, 0xe6, 0x11, 0xfb, 0x81, 0x5b, 0x6b, 0xbd, 0xd5, 0x68, 0xa8, 0x31, 0x6d, - 0x22, 0x97, 0x5b, 0x5f, 0x30, 0xe3, 0xed, 0xb8, 0x21, 0x75, 0x50, 0xe1, 0x7c, 0x16, 0x32, 0x7c, - 0x12, 0x55, 0xb1, 0xf5, 0x7c, 0xd9, 0xd5, 0x59, 0x98, 0xf6, 0x49, 0x10, 0x19, 0x87, 0xe1, 0x85, - 0xac, 0x19, 0xfa, 0x9e, 0x1b, 0x52, 0xe3, 0x77, 0x28, 0x73, 0xa1, 0xd7, 0x02, 0x4a, 0x22, 0x6a, - 0xd2, 0x47, 0x3d, 0x1a, 0x46, 0x78, 0x1b, 0xd4, 0x30, 0xcb, 0x75, 0x57, 0x6f, 0xdd, 0x6e, 0xa4, - 0x71, 0xaa, 0x21, 0xe3, 0x14, 0x1f, 0x7c, 0xdf, 0x6a, 0x37, 0xfa, 0xad, 0x86, 0xbf, 0xdd, 0x69, - 0xb0, 0xa8, 0x97, 0x41, 0x26, 0xa3, 0x9e, 0x7a, 0x54, 0x53, 0xe5, 0x8e, 0x17, 0x60, 0xb6, 0xe7, - 0x87, 0x34, 0x88, 0xf8, 0xc9, 0xaa, 0xa6, 0xa0, 0xd8, 0x2d, 0xf5, 0x89, 0x63, 0xb7, 0x49, 0x14, - 0xdf, 0x42, 0xd5, 0x4c, 0x68, 0xe3, 0xe3, 0x2c, 0xfa, 0x07, 0x7e, 0xfb, 0xf3, 0x42, 0xaf, 0xa2, - 0xac, 0x0c, 0xa1, 0xfc, 0x20, 0x8b, 0xf2, 0x35, 0xea, 0xd0, 0x14, 0x65, 0x9e, 0x61, 0x6a, 0x30, - 0x67, 0x91, 0xd0, 0x22, 0x6d, 0xc9, 0x4b, 0x92, 0x2c, 0x2c, 0xf8, 0x81, 0xe7, 0x93, 0x0e, 0xe7, - 0x74, 0xcf, 0x73, 0x6c, 0x6b, 0x20, 0x6c, 0x73, 0xf4, 0x87, 0x11, 0x23, 0x9e, 0xce, 0x31, 0xe2, - 0x13, 0x50, 0xdf, 0x18, 0xb8, 0xd6, 0xeb, 0x3e, 0x4f, 0x99, 0xcc, 0xc5, 0xec, 0x88, 0x76, 0x43, - 0x0d, 0xf1, 0xb8, 0x1f, 0x13, 0xc6, 0x87, 0x33, 0xb0, 0xa0, 0x9c, 0x80, 0x6d, 0x28, 0xc2, 0x5f, - 0xe4, 0xf4, 0x0b, 0x30, 0xdb, 0x0e, 0x06, 0x66, 0xcf, 0x15, 0x97, 0x29, 0x28, 0x26, 0xd8, 0x0f, - 0x7a, 0x6e, 0x0c, 0xb2, 0x6a, 0xc6, 0x04, 0xde, 0x84, 0x6a, 0x18, 0xb1, 0x24, 0xd9, 0x19, 0xf0, - 0x70, 0x54, 0x6f, 0x7d, 0x73, 0x77, 0x17, 0xc8, 0xa0, 0x6f, 0x08, 0x8e, 0x66, 0xc2, 0x1b, 0x3f, - 0x82, 0x9a, 0x8c, 0x84, 0xa1, 0x36, 0xb7, 0x34, 0xb5, 0x5c, 0x6f, 0x6d, 0xec, 0x5e, 0xd0, 0xeb, - 0x3e, 0x4b, 0xf0, 0x4a, 0xd4, 0x37, 0x53, 0x29, 0x78, 0x11, 0x6a, 0x5d, 0xe1, 0xeb, 0xa1, 0x56, - 0xe5, 0xda, 0x4e, 0x27, 0xf0, 0x77, 0x61, 0xc6, 0x76, 0x37, 0xbd, 0x50, 0xab, 0x71, 0x30, 0x57, - 0x77, 0x07, 0xe6, 0xb6, 0xbb, 0xe9, 0x99, 0x31, 0x43, 0xfc, 0x08, 0xf6, 0x05, 0x34, 0x0a, 0x06, - 0x52, 0x0b, 0x1a, 0x70, 0xbd, 0x7e, 0x6b, 0x77, 0x12, 0x4c, 0x95, 0xa5, 0x99, 0x95, 0x80, 0xd7, - 0xa0, 0x1e, 0xa6, 0x36, 0xa6, 0xd5, 0xb9, 0x40, 0x2d, 0xc3, 0x48, 0xb1, 0x41, 0x53, 0x5d, 0x3c, - 0x62, 0xc3, 0xf3, 0x39, 0x36, 0xfc, 0x4f, 0x04, 0x8b, 0x23, 0x61, 0x60, 0xc3, 0xa7, 0x85, 0x46, - 0x4a, 0x60, 0x3a, 0xf4, 0xa9, 0xc5, 0x23, 0x7f, 0xbd, 0x75, 0x67, 0xcf, 0xe2, 0x02, 0x97, 0xcb, - 0x59, 0x17, 0x85, 0xae, 0x52, 0xbe, 0xf9, 0x13, 0x04, 0x5f, 0x54, 0x38, 0xdf, 0x23, 0x91, 0xb5, - 0x55, 0x74, 0x24, 0xe6, 0x43, 0x6c, 0x8d, 0xc8, 0x66, 0x31, 0xc1, 0x0c, 0x8d, 0x0f, 0xee, 0x0f, - 0x7c, 0x06, 0x83, 0xfd, 0x92, 0x4e, 0x94, 0x4a, 0xfa, 0xef, 0x22, 0xd0, 0xd5, 0xc8, 0xe7, 0x39, - 0xce, 0x9b, 0xc4, 0xda, 0x2e, 0x82, 0xb2, 0x1f, 0x2a, 0x76, 0x9b, 0xe3, 0x98, 0x32, 0x2b, 0x76, - 0x7b, 0x87, 0x6e, 0x3f, 0x0c, 0x6a, 0x36, 0x07, 0xd4, 0xa7, 0x43, 0xa0, 0xa4, 0x8b, 0x15, 0x80, - 0x5a, 0x84, 0x9a, 0x3b, 0x54, 0x4c, 0xa5, 0x13, 0x39, 0x45, 0x54, 0x65, 0xa4, 0x88, 0xd2, 0x60, - 0xae, 0x9f, 0x54, 0xbd, 0xec, 0x67, 0x49, 0xb2, 0x83, 0x74, 0x02, 0xaf, 0xe7, 0x0b, 0x05, 0xc6, - 0x04, 0x43, 0xb1, 0x6d, 0xbb, 0x6d, 0x6d, 0x36, 0x46, 0xc1, 0xc6, 0xa5, 0xea, 0xdc, 0xf7, 0x2a, - 0xf0, 0xa5, 0x9c, 0xc3, 0x4d, 0xb4, 0x80, 0xe7, 0xe3, 0x84, 0x89, 0x1d, 0xce, 0x8d, 0xb5, 0xc3, - 0xea, 0x24, 0x3b, 0xac, 0xe5, 0x68, 0xe5, 0x9d, 0x0a, 0x2c, 0xe5, 0x68, 0x65, 0x72, 0x42, 0x7d, - 0x6e, 0xd4, 0xb2, 0xe9, 0x05, 0xe2, 0xc6, 0xab, 0x66, 0x4c, 0x30, 0xcf, 0xf0, 0x02, 0x7f, 0x8b, - 0xb8, 0x5a, 0x35, 0xf6, 0x8c, 0x98, 0x2a, 0xa5, 0x90, 0xff, 0x22, 0xd0, 0xa4, 0x16, 0xae, 0x58, - 0x5c, 0x27, 0x3d, 0xf7, 0xf9, 0x57, 0xc4, 0x02, 0xcc, 0x12, 0x8e, 0x56, 0x18, 0x88, 0xa0, 0x46, - 0x8e, 0x5c, 0xcd, 0x8f, 0x89, 0x47, 0xb2, 0x47, 0x0e, 0xd7, 0xed, 0x30, 0x92, 0x05, 0x2d, 0xde, - 0x84, 0xb9, 0x98, 0x5b, 0x5c, 0xc2, 0xd4, 0x5b, 0xeb, 0xbb, 0x4d, 0x6c, 0x19, 0xf5, 0x4a, 0xe6, - 0xc6, 0xcb, 0x70, 0x24, 0x37, 0xfa, 0x08, 0x18, 0x3a, 0x54, 0x65, 0x32, 0x17, 0x17, 0x90, 0xd0, - 0xc6, 0x7f, 0xa6, 0xb2, 0x61, 0xdd, 0x6b, 0xaf, 0x7b, 0x9d, 0x82, 0xb7, 0x60, 0xf1, 0xa5, 0x69, - 0x30, 0xe7, 0x7b, 0x6d, 0xe5, 0xd9, 0x27, 0x49, 0xb6, 0xcf, 0xf2, 0xdc, 0x88, 0xd8, 0x2e, 0x0d, - 0x44, 0x7e, 0x49, 0x27, 0x98, 0xb2, 0x43, 0xdb, 0xb5, 0xe8, 0x06, 0xb5, 0x3c, 0xb7, 0x1d, 0xf2, - 0x5b, 0x9b, 0x32, 0x33, 0x73, 0xf8, 0x16, 0xd4, 0x38, 0x7d, 0xdf, 0xee, 0xc6, 0x41, 0xb8, 0xde, - 0x5a, 0x69, 0xc4, 0xad, 0x92, 0x86, 0xda, 0x2a, 0x49, 0x75, 0xd8, 0xa5, 0x11, 0x69, 0xf4, 0x2f, - 0x36, 0xd8, 0x0e, 0x33, 0xdd, 0xcc, 0xb0, 0x44, 0xc4, 0x76, 0xd6, 0x6d, 0x97, 0x17, 0x58, 0x4c, - 0x54, 0x3a, 0xc1, 0x0c, 0x62, 0xd3, 0x73, 0x1c, 0xef, 0xb1, 0xf4, 0x81, 0x98, 0x62, 0xbb, 0x7a, - 0x6e, 0x64, 0x3b, 0x5c, 0x7e, 0xec, 0x00, 0xe9, 0x04, 0xdf, 0x65, 0x3b, 0x11, 0x0d, 0x78, 0x09, - 0x53, 0x33, 0x05, 0x95, 0x98, 0x5c, 0x3d, 0xee, 0x0b, 0x48, 0xdf, 0x8b, 0x8d, 0x73, 0x5e, 0x35, - 0xce, 0x61, 0x83, 0xdf, 0x97, 0xf3, 0x6e, 0xe6, 0xcd, 0x10, 0xda, 0xb7, 0xbd, 0x5e, 0xa8, 0xed, - 0x8f, 0x93, 0xb8, 0xa4, 0x47, 0x0c, 0xf6, 0x40, 0x8e, 0xc1, 0xfe, 0x1e, 0x41, 0x75, 0xdd, 0xeb, - 0x5c, 0x77, 0xa3, 0x60, 0xc0, 0x2b, 0x7b, 0xcf, 0x8d, 0xa8, 0x2b, 0xad, 0x42, 0x92, 0x4c, 0xd5, - 0x91, 0xdd, 0xa5, 0x1b, 0x11, 0xe9, 0xfa, 0xa2, 0x26, 0xd9, 0x91, 0xaa, 0x93, 0xcd, 0xec, 0xf8, - 0x0e, 0x09, 0x23, 0xee, 0xbd, 0x55, 0x93, 0x8f, 0x19, 0xd0, 0x64, 0xc1, 0x46, 0x14, 0x08, 0xd7, - 0xcd, 0xcc, 0xa9, 0x86, 0x34, 0x13, 0x63, 0x13, 0xa4, 0xb1, 0x01, 0x2f, 0x25, 0xa5, 0xec, 0x7d, - 0x1a, 0x74, 0x6d, 0x97, 0x14, 0xc7, 0xdb, 0x32, 0x5d, 0x98, 0x07, 0x19, 0x07, 0x62, 0xf5, 0xdf, - 0x43, 0xdb, 0x6d, 0x7b, 0x8f, 0x0b, 0x1c, 0xa1, 0x0c, 0xdb, 0xbf, 0x65, 0xfb, 0x2d, 0x0a, 0xdf, - 0xc4, 0x37, 0x6f, 0xc1, 0x3e, 0xe6, 0xc5, 0x7d, 0x2a, 0x7e, 0x10, 0x81, 0xc2, 0x18, 0xf7, 0x24, - 0x4f, 0x79, 0x98, 0xd9, 0x8d, 0x78, 0x1d, 0x0e, 0x90, 0x30, 0xb4, 0x3b, 0x2e, 0x6d, 0x4b, 0x5e, - 0x95, 0xd2, 0xbc, 0x86, 0xb7, 0xc6, 0xcf, 0x3e, 0xbe, 0x42, 0xdc, 0x9d, 0x24, 0x8d, 0x1f, 0x23, - 0x38, 0x9c, 0xcb, 0x24, 0xb1, 0x75, 0xa4, 0x84, 0x57, 0x1d, 0xaa, 0xa1, 0xb5, 0x45, 0xdb, 0x3d, - 0x87, 0xca, 0xbe, 0x86, 0xa4, 0xd9, 0x6f, 0xed, 0x5e, 0x7c, 0x93, 0x22, 0xbc, 0x27, 0x34, 0x3e, - 0x06, 0xd0, 0x25, 0x6e, 0x8f, 0x38, 0x1c, 0xc2, 0x34, 0x87, 0xa0, 0xcc, 0x18, 0x8b, 0xa0, 0xe7, - 0x99, 0x81, 0xe8, 0x24, 0xfc, 0x03, 0xc1, 0x7e, 0x19, 0x06, 0xc5, 0x1d, 0x2e, 0xc3, 0x01, 0x45, - 0x0d, 0x77, 0xd3, 0xeb, 0x1c, 0x9e, 0x9e, 0x10, 0xe2, 0xa4, 0x2d, 0x4c, 0x65, 0xbb, 0x97, 0xfd, - 0x4c, 0xff, 0xb1, 0x74, 0x1e, 0x42, 0x3b, 0xaa, 0xc4, 0x7e, 0x04, 0xda, 0x1d, 0xe2, 0x92, 0x0e, - 0x6d, 0x27, 0x87, 0x4b, 0x0c, 0xe9, 0x07, 0xea, 0x63, 0x79, 0xd7, 0x4f, 0xd3, 0xa4, 0x9c, 0xb1, - 0x37, 0x37, 0xe5, 0xc3, 0x3b, 0x80, 0xea, 0xba, 0xed, 0x6e, 0xb3, 0xf7, 0x1b, 0x3b, 0x57, 0x64, - 0x47, 0x8e, 0xd4, 0x61, 0x4c, 0xe0, 0x83, 0x30, 0xd5, 0x0b, 0x1c, 0x71, 0xcf, 0x6c, 0x88, 0x97, - 0xa0, 0xde, 0xa6, 0xa1, 0x15, 0xd8, 0xbe, 0xb8, 0x65, 0xde, 0xe8, 0x53, 0xa6, 0x98, 0xb6, 0x6d, - 0xcb, 0x73, 0xaf, 0x39, 0x24, 0x0c, 0x65, 0x62, 0x48, 0x26, 0x8c, 0x57, 0x61, 0x1f, 0x93, 0x99, - 0x1e, 0xf3, 0x5c, 0xf6, 0x98, 0x87, 0x33, 0xf0, 0x25, 0x3c, 0x89, 0xf8, 0x26, 0xbc, 0xc0, 0xf2, - 0xf1, 0x15, 0xdf, 0x17, 0x4c, 0x4a, 0x16, 0x23, 0x53, 0x43, 0x97, 0xde, 0xfa, 0xa9, 0x01, 0x58, - 0xb5, 0x79, 0x1a, 0xf4, 0x6d, 0x8b, 0xe2, 0x77, 0x11, 0x4c, 0x33, 0x01, 0xf8, 0xe8, 0x38, 0x17, - 0xe3, 0xb6, 0xa7, 0xef, 0xdd, 0x83, 0x8e, 0x49, 0x33, 0x16, 0xdf, 0xfa, 0xfb, 0xbf, 0xdf, 0xab, - 0x2c, 0xe0, 0x17, 0xf9, 0x67, 0x84, 0xfe, 0x45, 0xb5, 0xa5, 0x1f, 0xe2, 0xb7, 0x11, 0x60, 0x51, - 0x85, 0x28, 0xdd, 0x5d, 0x7c, 0x6e, 0x1c, 0xc4, 0x9c, 0x2e, 0xb0, 0x7e, 0x54, 0x89, 0xf6, 0x0d, - 0xcb, 0x0b, 0x28, 0x8b, 0xed, 0x7c, 0x01, 0x07, 0xb0, 0xc2, 0x01, 0x9c, 0xc4, 0x46, 0x1e, 0x80, - 0xe6, 0x13, 0xa6, 0xb7, 0xa7, 0x4d, 0x1a, 0xcb, 0xfd, 0x08, 0xc1, 0xcc, 0x43, 0x5e, 0x73, 0x4f, - 0x50, 0xd2, 0xc6, 0x9e, 0x29, 0x89, 0x8b, 0xe3, 0x68, 0x8d, 0x13, 0x1c, 0xe9, 0x51, 0x7c, 0x44, - 0x22, 0x0d, 0xa3, 0x80, 0x92, 0x6e, 0x06, 0xf0, 0x05, 0x84, 0x3f, 0x41, 0x30, 0x1b, 0xb7, 0x1b, - 0xf1, 0xa9, 0x71, 0x28, 0x33, 0xed, 0x48, 0x7d, 0xef, 0x7a, 0x77, 0xc6, 0x59, 0x8e, 0xf1, 0x84, - 0x91, 0x7b, 0x9d, 0x6b, 0x99, 0xce, 0xde, 0xfb, 0x08, 0xa6, 0x6e, 0xd2, 0x89, 0xf6, 0xb6, 0x87, - 0xe0, 0x46, 0x14, 0x98, 0x73, 0xd5, 0xf8, 0x63, 0x04, 0x2f, 0xdd, 0xa4, 0x51, 0x7e, 0xaa, 0xc3, - 0xcb, 0x93, 0xf3, 0x8f, 0x30, 0xbb, 0x73, 0x25, 0x56, 0x26, 0x31, 0xbe, 0xc9, 0x91, 0x9d, 0xc5, - 0x67, 0x8a, 0x8c, 0x30, 0x1c, 0xb8, 0xd6, 0x63, 0x81, 0xe3, 0xcf, 0x08, 0x0e, 0x0e, 0x7f, 0x6b, - 0xc1, 0xd9, 0xe4, 0x98, 0xfb, 0x29, 0x46, 0xbf, 0xbb, 0xdb, 0x58, 0x9a, 0x65, 0x6a, 0x5c, 0xe1, - 0xc8, 0x5f, 0xc1, 0x2f, 0x17, 0x21, 0x97, 0x4d, 0xca, 0xb0, 0xf9, 0x44, 0x0e, 0x9f, 0xf2, 0x8f, - 0x7f, 0x1c, 0xf6, 0x5b, 0x08, 0xe6, 0x6f, 0xd2, 0xe8, 0x4e, 0xd2, 0xa3, 0x3b, 0x55, 0xaa, 0x87, - 0xaf, 0x2f, 0x36, 0x94, 0x6f, 0x74, 0xf2, 0xa7, 0x44, 0xa5, 0xab, 0x1c, 0xd8, 0x19, 0x7c, 0xaa, - 0x08, 0x58, 0xda, 0x17, 0xfc, 0x08, 0xc1, 0x61, 0x15, 0x44, 0xfa, 0x85, 0xe3, 0x2b, 0x3b, 0xfb, - 0xa2, 0x20, 0xbe, 0x4b, 0x4c, 0x40, 0xd7, 0xe2, 0xe8, 0xce, 0x1b, 0xf9, 0x17, 0xde, 0x1d, 0x41, - 0xb1, 0x86, 0x56, 0x96, 0x11, 0xfe, 0x03, 0x82, 0xd9, 0xb8, 0x09, 0x37, 0x5e, 0x47, 0x99, 0x5e, - 0xfd, 0x5e, 0x7a, 0xcf, 0x75, 0x0e, 0xf9, 0xeb, 0xfa, 0x85, 0x7c, 0x85, 0xaa, 0xfb, 0xe5, 0xd5, - 0x36, 0xb8, 0x96, 0xb3, 0x6e, 0xff, 0x1b, 0x04, 0x90, 0x36, 0x12, 0xf1, 0xd9, 0xe2, 0x73, 0x28, - 0xcd, 0x46, 0x7d, 0x6f, 0x5b, 0x89, 0x46, 0x83, 0x9f, 0x67, 0x59, 0x5f, 0x2a, 0xf4, 0x39, 0x9f, - 0x5a, 0x6b, 0x71, 0xd3, 0xf1, 0x97, 0x08, 0x66, 0x78, 0x9f, 0x08, 0x9f, 0x1c, 0x87, 0x59, 0x6d, - 0x23, 0xed, 0xa5, 0xea, 0x4f, 0x73, 0xa8, 0x4b, 0xad, 0xa2, 0xc0, 0xb5, 0x86, 0x56, 0x70, 0x1f, - 0x66, 0xe3, 0x9e, 0xcd, 0x78, 0xf3, 0xc8, 0xf4, 0x74, 0xf4, 0xa5, 0x82, 0x44, 0x1a, 0x1b, 0xaa, - 0x88, 0x99, 0x2b, 0x93, 0x62, 0xe6, 0x34, 0x0b, 0x6b, 0xf8, 0x44, 0x51, 0xd0, 0xfb, 0x0c, 0x14, - 0x73, 0x8e, 0xa3, 0x3b, 0x65, 0x2c, 0x4d, 0x8a, 0x9b, 0x4c, 0x3b, 0x3f, 0x47, 0x70, 0x70, 0xb8, - 0xe4, 0xc4, 0x47, 0x86, 0x62, 0xa6, 0x5a, 0x67, 0xeb, 0x59, 0x2d, 0x8e, 0x2b, 0x57, 0x8d, 0x6f, - 0x70, 0x14, 0x6b, 0xf8, 0xf2, 0x44, 0xcf, 0xb8, 0x2b, 0xa3, 0x0e, 0x63, 0xb4, 0x9a, 0x7e, 0xb3, - 0xf8, 0x2d, 0x82, 0x79, 0xc9, 0xf7, 0x7e, 0x40, 0x69, 0x31, 0xac, 0xbd, 0x73, 0x04, 0x26, 0xcb, - 0x78, 0x95, 0xc3, 0xff, 0x2a, 0xbe, 0x54, 0x12, 0xbe, 0x84, 0xbd, 0x1a, 0x31, 0xa4, 0x7f, 0x44, - 0x70, 0xe8, 0x61, 0x6c, 0xf7, 0x9f, 0x13, 0xfe, 0x6b, 0x1c, 0xff, 0xd7, 0xf0, 0x2b, 0x05, 0x75, - 0xd1, 0xa4, 0x63, 0x5c, 0x40, 0xf8, 0xd7, 0x08, 0xaa, 0xb2, 0x03, 0x8f, 0xcf, 0x8c, 0x75, 0x8c, - 0x6c, 0x8f, 0x7e, 0x2f, 0x8d, 0x59, 0x14, 0x01, 0xc6, 0xc9, 0xc2, 0x54, 0x2a, 0xe4, 0x33, 0x83, - 0x7e, 0x1f, 0x01, 0x4e, 0xde, 0x8b, 0xc9, 0x0b, 0x12, 0x9f, 0xce, 0x88, 0x1a, 0xdb, 0x60, 0xd0, - 0xcf, 0x4c, 0x5c, 0x97, 0x4d, 0xa5, 0x2b, 0x85, 0xa9, 0xd4, 0x4b, 0xe4, 0xbf, 0x83, 0xa0, 0x7e, - 0x93, 0x26, 0x35, 0x7b, 0x81, 0x2e, 0xb3, 0x9f, 0x16, 0xf4, 0xe5, 0xc9, 0x0b, 0x05, 0xa2, 0xf3, - 0x1c, 0xd1, 0x69, 0x5c, 0xac, 0x2a, 0x09, 0xe0, 0x43, 0x04, 0xfb, 0xee, 0xa9, 0x26, 0x8a, 0xcf, - 0x4f, 0x92, 0x94, 0x89, 0xe4, 0xe5, 0x71, 0x7d, 0x99, 0xe3, 0x5a, 0x35, 0x4a, 0xe1, 0x5a, 0x13, - 0xfd, 0xfb, 0x5f, 0xa0, 0xf8, 0x69, 0x37, 0xd4, 0x7d, 0xfd, 0x7f, 0xf5, 0x56, 0xd0, 0xc4, 0x35, - 0x2e, 0x71, 0x7c, 0x0d, 0x7c, 0xbe, 0x0c, 0xbe, 0xa6, 0x68, 0xc9, 0xe2, 0x0f, 0x10, 0x1c, 0xe2, - 0xfd, 0x6f, 0x95, 0xf1, 0x50, 0x8a, 0x19, 0xd7, 0x2d, 0x2f, 0x91, 0x62, 0x44, 0xfc, 0x31, 0x76, - 0x04, 0x6a, 0x4d, 0xf6, 0xb6, 0x7f, 0x86, 0x60, 0xbf, 0x4c, 0x6a, 0xe2, 0x76, 0x57, 0x27, 0x29, - 0x6e, 0xa7, 0x49, 0x50, 0x98, 0xdb, 0x4a, 0x39, 0x73, 0xfb, 0x04, 0xc1, 0x9c, 0xe8, 0x3d, 0x17, - 0x94, 0x0a, 0x4a, 0x73, 0x5a, 0x1f, 0x7a, 0xf9, 0x8b, 0xa6, 0xa6, 0xf1, 0x3d, 0x2e, 0xf6, 0x01, - 0x6e, 0x16, 0x89, 0xf5, 0xbd, 0x76, 0xd8, 0x7c, 0x22, 0x3a, 0x8a, 0x4f, 0x9b, 0x8e, 0xd7, 0x09, - 0xdf, 0x30, 0x70, 0x61, 0x42, 0x64, 0x6b, 0x2e, 0x20, 0x1c, 0x41, 0x8d, 0x19, 0x07, 0x6f, 0x27, - 0xe0, 0xa5, 0xa1, 0xe6, 0xc3, 0x48, 0xa7, 0x41, 0xd7, 0x47, 0xda, 0x13, 0x69, 0x06, 0x14, 0xcf, - 0x3e, 0x7c, 0xbc, 0x50, 0x2c, 0x17, 0xf4, 0x36, 0x82, 0x43, 0xaa, 0xb5, 0xc7, 0xe2, 0x4b, 0xdb, - 0x7a, 0x11, 0x0a, 0x51, 0x54, 0xe3, 0x95, 0x52, 0x86, 0xc4, 0xe1, 0x5c, 0xbd, 0xf1, 0xa7, 0x67, - 0xc7, 0xd0, 0x5f, 0x9f, 0x1d, 0x43, 0xff, 0x7a, 0x76, 0x0c, 0xbd, 0x71, 0xb9, 0xdc, 0x1f, 0x0f, - 0x2d, 0xc7, 0xa6, 0x6e, 0xa4, 0xb2, 0xff, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x83, 0x0c, 0x3f, - 0x61, 0x5e, 0x29, 0x00, 0x00, + 0x15, 0xa7, 0x66, 0xbf, 0x66, 0xde, 0xec, 0xfa, 0xa3, 0x12, 0x2f, 0x9d, 0xf6, 0xc6, 0x6c, 0xda, + 0x76, 0xbc, 0x59, 0x7b, 0x67, 0xec, 0xc1, 0x20, 0x67, 0x93, 0x08, 0xec, 0xf5, 0x27, 0xac, 0x1d, + 0xd3, 0x6b, 0x63, 0x14, 0x0e, 0x50, 0xe9, 0xae, 0x9d, 0x6d, 0xb6, 0xa7, 0xbb, 0xdd, 0xdd, 0x33, + 0xd6, 0xca, 0xf8, 0x12, 0x64, 0x09, 0xa1, 0x08, 0x04, 0xe4, 0x80, 0x10, 0x02, 0x14, 0x14, 0x09, + 0x21, 0x10, 0x17, 0x14, 0x21, 0x21, 0x24, 0xb8, 0x20, 0x38, 0x20, 0x21, 0x38, 0x72, 0x41, 0x16, + 0xe2, 0x08, 0x97, 0xfc, 0x01, 0xa8, 0xaa, 0xab, 0xba, 0xab, 0xe7, 0xa3, 0x67, 0x96, 0x19, 0x14, + 0xdf, 0xfa, 0xd5, 0x54, 0xbd, 0xf7, 0xab, 0x57, 0xbf, 0x7a, 0xaf, 0xea, 0xd5, 0xc0, 0x89, 0x88, + 0x86, 0x1d, 0x1a, 0xd6, 0x49, 0x10, 0xb8, 0x8e, 0x45, 0x62, 0xc7, 0xf7, 0xd4, 0xef, 0x5a, 0x10, + 0xfa, 0xb1, 0x8f, 0xab, 0x4a, 0x93, 0xbe, 0xd4, 0xf4, 0xfd, 0xa6, 0x4b, 0xeb, 0x24, 0x70, 0xea, + 0xc4, 0xf3, 0xfc, 0x98, 0x37, 0x47, 0x49, 0x57, 0xdd, 0xd8, 0xbd, 0x10, 0xd5, 0x1c, 0x9f, 0xff, + 0x6a, 0xf9, 0x21, 0xad, 0x77, 0xce, 0xd5, 0x9b, 0xd4, 0xa3, 0x21, 0x89, 0xa9, 0x2d, 0xfa, 0x9c, + 0xcf, 0xfa, 0xb4, 0x88, 0xb5, 0xe3, 0x78, 0x34, 0xdc, 0xab, 0x07, 0xbb, 0x4d, 0xd6, 0x10, 0xd5, + 0x5b, 0x34, 0x26, 0xfd, 0x46, 0x6d, 0x36, 0x9d, 0x78, 0xa7, 0xfd, 0x66, 0xcd, 0xf2, 0x5b, 0x75, + 0x12, 0x36, 0xfd, 0x20, 0xf4, 0xbf, 0xc2, 0x3f, 0xd6, 0x2c, 0xbb, 0xde, 0x69, 0x64, 0x0a, 0xd4, + 0xb9, 0x74, 0xce, 0x11, 0x37, 0xd8, 0x21, 0xbd, 0xda, 0xae, 0x0c, 0xd1, 0x16, 0xd2, 0xc0, 0x17, + 0xbe, 0xe1, 0x9f, 0x4e, 0xec, 0x87, 0x7b, 0xca, 0x67, 0xa2, 0xc6, 0xf8, 0x00, 0xc1, 0xa1, 0x8b, + 0x99, 0xbd, 0xcf, 0xb5, 0x69, 0xb8, 0x87, 0x31, 0x4c, 0x7b, 0xa4, 0x45, 0x35, 0xb4, 0x8c, 0x56, + 0x2a, 0x26, 0xff, 0xc6, 0x1a, 0xcc, 0x85, 0x74, 0x3b, 0xa4, 0xd1, 0x8e, 0x56, 0xe2, 0xcd, 0x52, + 0xc4, 0x3a, 0x94, 0x99, 0x71, 0x6a, 0xc5, 0x91, 0x36, 0xb5, 0x3c, 0xb5, 0x52, 0x31, 0x53, 0x19, + 0xaf, 0xc0, 0xc1, 0x90, 0x46, 0x7e, 0x3b, 0xb4, 0xe8, 0xe7, 0x69, 0x18, 0x39, 0xbe, 0xa7, 0x4d, + 0xf3, 0xd1, 0xdd, 0xcd, 0x4c, 0x4b, 0x44, 0x5d, 0x6a, 0xc5, 0x7e, 0xa8, 0xcd, 0xf0, 0x2e, 0xa9, + 0xcc, 0xf0, 0x30, 0xe0, 0xda, 0x6c, 0x82, 0x87, 0x7d, 0x63, 0x03, 0xe6, 0x49, 0x10, 0xdc, 0x22, + 0x2d, 0x1a, 0x05, 0xc4, 0xa2, 0xda, 0x1c, 0xff, 0x2d, 0xd7, 0xc6, 0x30, 0x0b, 0x24, 0x5a, 0x99, + 0x03, 0x93, 0xa2, 0xb1, 0x01, 0x95, 0x5b, 0xbe, 0x4d, 0x07, 0x4f, 0xb7, 0x5b, 0x7d, 0xa9, 0x57, + 0xbd, 0xf1, 0x18, 0xc1, 0x11, 0x93, 0x76, 0x1c, 0x86, 0xff, 0x26, 0x8d, 0x89, 0x4d, 0x62, 0xd2, + 0xad, 0xb1, 0x94, 0x6a, 0xd4, 0xa1, 0x1c, 0x8a, 0xce, 0x5a, 0x89, 0xb7, 0xa7, 0x72, 0x8f, 0xb5, + 0xa9, 0xe2, 0xc9, 0x24, 0x2e, 0x4c, 0x27, 0xf3, 0x2f, 0x04, 0xc7, 0x94, 0x35, 0x34, 0x85, 0x67, + 0xaf, 0x74, 0xa8, 0x17, 0x47, 0x83, 0x01, 0x9d, 0x81, 0xc3, 0x72, 0x11, 0xba, 0xe7, 0xd9, 0xfb, + 0x03, 0x83, 0xa8, 0x36, 0x4a, 0x88, 0x6a, 0x1b, 0x5e, 0x86, 0xaa, 0x94, 0xef, 0xde, 0xb8, 0x2c, + 0x60, 0xaa, 0x4d, 0x3d, 0x13, 0x9d, 0x29, 0x9e, 0xe8, 0x6c, 0x7e, 0xa2, 0x5f, 0x47, 0xa0, 0x29, + 0x13, 0xbd, 0x49, 0x3c, 0x67, 0x9b, 0x46, 0xf1, 0xa8, 0x3e, 0x47, 0x13, 0xf4, 0xf9, 0x0b, 0x50, + 0xb9, 0xea, 0xb8, 0x74, 0x63, 0xa7, 0xed, 0xed, 0xe2, 0x67, 0x61, 0xc6, 0x62, 0x1f, 0xdc, 0xf6, + 0xbc, 0x99, 0x08, 0xc6, 0xb7, 0x11, 0xbc, 0x30, 0x08, 0xed, 0x3d, 0x27, 0xde, 0x61, 0xe3, 0xa3, + 0x41, 0xb0, 0xad, 0x1d, 0x6a, 0xed, 0x46, 0xed, 0x96, 0xa4, 0x8a, 0x94, 0xc7, 0x84, 0xfd, 0x33, + 0x04, 0x2b, 0x43, 0x31, 0xdd, 0x0b, 0x49, 0x10, 0xd0, 0x10, 0x5f, 0x85, 0x99, 0xfb, 0xec, 0x07, + 0xbe, 0x31, 0xaa, 0x8d, 0x5a, 0x4d, 0x0d, 0xac, 0x43, 0xb5, 0x5c, 0xff, 0x88, 0x99, 0x0c, 0xc7, + 0x35, 0xe9, 0x9e, 0x12, 0xd7, 0xb3, 0x98, 0xd3, 0x93, 0x7a, 0x91, 0xf5, 0xe7, 0xdd, 0x2e, 0xcd, + 0xc2, 0x74, 0x40, 0xc2, 0xd8, 0x38, 0x02, 0xcf, 0xe4, 0x69, 0x1d, 0xf8, 0x5e, 0x44, 0x8d, 0xdf, + 0xe4, 0x59, 0xb0, 0x11, 0x52, 0x12, 0x53, 0x93, 0xde, 0x6f, 0xd3, 0x28, 0xc6, 0xbb, 0xa0, 0xc6, + 0x7a, 0xee, 0xd5, 0x6a, 0xe3, 0x46, 0x2d, 0x0b, 0x96, 0x35, 0x19, 0x2c, 0xf9, 0xc7, 0x97, 0x2c, + 0xbb, 0xd6, 0x69, 0xd4, 0x82, 0xdd, 0x66, 0x8d, 0x85, 0xde, 0x1c, 0x32, 0x19, 0x7a, 0xd5, 0xa9, + 0x9a, 0xaa, 0x76, 0xbc, 0x08, 0xb3, 0xed, 0x20, 0xa2, 0x61, 0xcc, 0x67, 0x56, 0x36, 0x85, 0xc4, + 0xd6, 0xaf, 0x43, 0x5c, 0xc7, 0x26, 0x71, 0xb2, 0x3e, 0x65, 0x33, 0x95, 0x8d, 0xdf, 0xe6, 0xd1, + 0xdf, 0x0d, 0xec, 0x0f, 0x0b, 0xbd, 0x8a, 0xb2, 0x94, 0x47, 0xa9, 0x32, 0x68, 0x2a, 0xcf, 0xa0, + 0x5f, 0xe5, 0xf1, 0x5f, 0xa6, 0x2e, 0xcd, 0xf0, 0xf7, 0x23, 0xb3, 0x06, 0x73, 0x16, 0x89, 0x2c, + 0x62, 0x4b, 0x2b, 0x52, 0x64, 0x01, 0x28, 0x08, 0xfd, 0x80, 0x34, 0xb9, 0xa6, 0xdb, 0xbe, 0xeb, + 0x58, 0x7b, 0xc2, 0x5c, 0xef, 0x0f, 0x3d, 0xc4, 0x9f, 0x2e, 0x26, 0xfe, 0x4c, 0x1e, 0xf6, 0x71, + 0xa8, 0x6e, 0xed, 0x79, 0xd6, 0xeb, 0x01, 0xcf, 0xf5, 0x6c, 0xc7, 0x3a, 0x31, 0x6d, 0x45, 0x1a, + 0xe2, 0x79, 0x21, 0x11, 0x8c, 0xf7, 0x67, 0x60, 0x51, 0x99, 0x1b, 0x1b, 0x50, 0x34, 0xb3, 0xa2, + 0xe8, 0xb2, 0x08, 0xb3, 0x76, 0xb8, 0x67, 0xb6, 0x3d, 0x41, 0x00, 0x21, 0x31, 0xc3, 0x41, 0xd8, + 0xf6, 0x12, 0xf8, 0x65, 0x33, 0x11, 0xf0, 0x36, 0x94, 0xa3, 0x98, 0x65, 0xf7, 0xe6, 0x1e, 0x07, + 0x5e, 0x6d, 0x7c, 0x66, 0xbc, 0x45, 0x67, 0xd0, 0xb7, 0x84, 0x46, 0x33, 0xd5, 0x8d, 0xef, 0x43, + 0x45, 0x46, 0xe3, 0x48, 0x9b, 0x5b, 0x9e, 0x5a, 0xa9, 0x36, 0xb6, 0xc6, 0x37, 0xf4, 0x7a, 0xc0, + 0x4e, 0x26, 0x4a, 0xe6, 0x31, 0x33, 0x2b, 0x78, 0x09, 0x2a, 0x2d, 0x11, 0x1f, 0x22, 0x91, 0x85, + 0xb3, 0x06, 0xfc, 0x05, 0x98, 0x71, 0xbc, 0x6d, 0x3f, 0xd2, 0x2a, 0x1c, 0xcc, 0xa5, 0xf1, 0xc0, + 0xdc, 0xf0, 0xb6, 0x7d, 0x33, 0x51, 0x88, 0xef, 0xc3, 0x42, 0x48, 0xe3, 0x70, 0x4f, 0x7a, 0x41, + 0x03, 0xee, 0xd7, 0xcf, 0x8e, 0x67, 0xc1, 0x54, 0x55, 0x9a, 0x79, 0x0b, 0x78, 0x1d, 0xaa, 0x51, + 0xc6, 0x31, 0xad, 0xca, 0x0d, 0x6a, 0x39, 0x45, 0x0a, 0x07, 0x4d, 0xb5, 0x73, 0x0f, 0xbb, 0xe7, + 0x8b, 0xd9, 0xbd, 0x90, 0x67, 0xf7, 0x7f, 0x10, 0x2c, 0xf5, 0x04, 0x95, 0xad, 0x80, 0x16, 0xd2, + 0x97, 0xc0, 0x74, 0x14, 0x50, 0x8b, 0x67, 0x98, 0x6a, 0xe3, 0xe6, 0xc4, 0xa2, 0x0c, 0xb7, 0xcb, + 0x55, 0x17, 0x05, 0xc2, 0x31, 0xf7, 0xf3, 0x8f, 0x10, 0x7c, 0x54, 0xb1, 0x79, 0x9b, 0xc4, 0xd6, + 0x4e, 0xd1, 0x64, 0xd9, 0xbe, 0x63, 0x7d, 0x44, 0x3e, 0x4d, 0x04, 0x46, 0x4e, 0xfe, 0x71, 0x67, + 0x2f, 0x60, 0x00, 0xd9, 0x2f, 0x59, 0xc3, 0x98, 0x87, 0x95, 0x9f, 0x23, 0xd0, 0xd5, 0xd8, 0xeb, + 0xbb, 0xee, 0x9b, 0xc4, 0xda, 0x2d, 0x02, 0x79, 0x00, 0x4a, 0x8e, 0xcd, 0x11, 0x4e, 0x99, 0x25, + 0xc7, 0xde, 0x67, 0x10, 0xe9, 0x86, 0x3b, 0x5b, 0x0c, 0x77, 0x2e, 0x0f, 0xf7, 0x83, 0x2e, 0xb8, + 0x72, 0x2b, 0x17, 0xc0, 0x5d, 0x82, 0x8a, 0xd7, 0x75, 0x70, 0xcc, 0x1a, 0xfa, 0x1c, 0x18, 0x4b, + 0x3d, 0x07, 0x46, 0x0d, 0xe6, 0x3a, 0xe9, 0xb5, 0x80, 0xfd, 0x2c, 0x45, 0x36, 0xc5, 0x66, 0xe8, + 0xb7, 0x03, 0xe1, 0xf4, 0x44, 0x60, 0x28, 0x76, 0x1d, 0xcf, 0xd6, 0x66, 0x13, 0x14, 0xec, 0x7b, + 0xff, 0x17, 0x81, 0xdc, 0xb4, 0x7f, 0x51, 0x82, 0x8f, 0xf5, 0x99, 0xf6, 0x50, 0x3e, 0x3d, 0x1d, + 0x73, 0x4f, 0x59, 0x3d, 0x37, 0x90, 0xd5, 0xe5, 0x61, 0xac, 0xae, 0x14, 0xfb, 0x0b, 0xf2, 0xfe, + 0xfa, 0x69, 0x09, 0x96, 0xfb, 0xf8, 0x6b, 0xf8, 0x31, 0xe0, 0xa9, 0x71, 0xd8, 0xb6, 0x1f, 0x0a, + 0x96, 0x94, 0xcd, 0x44, 0x60, 0xfb, 0xcc, 0x0f, 0x83, 0x1d, 0xe2, 0x71, 0x76, 0x94, 0x4d, 0x21, + 0x8d, 0xe9, 0xaa, 0x6f, 0x94, 0x40, 0x93, 0xfe, 0xb9, 0x68, 0x71, 0x6f, 0xb5, 0xbd, 0xa7, 0xdf, + 0x45, 0x8b, 0x30, 0x4b, 0x38, 0x5a, 0x41, 0x2a, 0x21, 0xf5, 0x38, 0xa3, 0x5c, 0xec, 0x8c, 0x4a, + 0xde, 0x19, 0x8f, 0x11, 0x1c, 0xcd, 0x3b, 0x23, 0xda, 0x74, 0xa2, 0x58, 0x1e, 0xea, 0xf1, 0x36, + 0xcc, 0x25, 0x76, 0x92, 0x23, 0x59, 0xb5, 0xb1, 0x39, 0x6e, 0xa2, 0xce, 0x39, 0x5e, 0x2a, 0x37, + 0x5e, 0x86, 0xa3, 0x7d, 0xa3, 0x9c, 0x80, 0xa1, 0x43, 0x59, 0x1e, 0x4e, 0xc4, 0xd2, 0xa4, 0xb2, + 0xf1, 0x78, 0x3a, 0x9f, 0x72, 0x7c, 0x7b, 0xd3, 0x6f, 0x16, 0xdc, 0xaf, 0x8b, 0x97, 0x93, 0xb9, + 0xca, 0xb7, 0x95, 0xab, 0xb4, 0x14, 0xd9, 0x38, 0xcb, 0xf7, 0x62, 0xe2, 0x78, 0x34, 0x14, 0x59, + 0x31, 0x6b, 0x60, 0xcb, 0x10, 0x39, 0x9e, 0x45, 0xb7, 0xa8, 0xe5, 0x7b, 0x76, 0xc4, 0xd7, 0x73, + 0xca, 0xcc, 0xb5, 0xe1, 0xeb, 0x50, 0xe1, 0xf2, 0x1d, 0xa7, 0x95, 0xa4, 0x81, 0x6a, 0x63, 0xb5, + 0x96, 0xd4, 0xac, 0x6a, 0x6a, 0xcd, 0x2a, 0xf3, 0x61, 0x8b, 0xc6, 0xa4, 0xd6, 0x39, 0x57, 0x63, + 0x23, 0xcc, 0x6c, 0x30, 0xc3, 0x12, 0x13, 0xc7, 0xdd, 0x74, 0x3c, 0x7e, 0x60, 0x64, 0xa6, 0xb2, + 0x06, 0x46, 0x95, 0x6d, 0xdf, 0x75, 0xfd, 0x07, 0x72, 0xdf, 0x24, 0x12, 0x1b, 0xd5, 0xf6, 0x62, + 0xc7, 0xe5, 0xf6, 0x13, 0x22, 0x64, 0x0d, 0x7c, 0x94, 0xe3, 0xc6, 0x34, 0x14, 0x1b, 0x46, 0x48, + 0x29, 0x19, 0xab, 0x49, 0x19, 0x46, 0xee, 0xd7, 0x84, 0xb6, 0xf3, 0x2a, 0x6d, 0xbb, 0xb7, 0xc2, + 0x42, 0x9f, 0x5a, 0x04, 0xaf, 0x4a, 0xd1, 0x8e, 0xe3, 0xb7, 0x23, 0xed, 0x40, 0x72, 0xf4, 0x90, + 0x72, 0x0f, 0x95, 0x0f, 0x16, 0x53, 0xf9, 0x50, 0x9e, 0xca, 0xbf, 0x43, 0x50, 0xde, 0xf4, 0x9b, + 0x57, 0xbc, 0x38, 0xdc, 0xe3, 0xb7, 0x1b, 0xdf, 0x8b, 0xa9, 0x27, 0xf9, 0x22, 0x45, 0xb6, 0x08, + 0xb1, 0xd3, 0xa2, 0x5b, 0x31, 0x69, 0x05, 0xe2, 0x8c, 0xb5, 0xaf, 0x45, 0x48, 0x07, 0x33, 0xc7, + 0xb8, 0x24, 0x8a, 0xf9, 0x8e, 0x2f, 0x9b, 0xfc, 0x9b, 0x4d, 0x21, 0xed, 0xb0, 0x15, 0x87, 0x62, + 0xbb, 0xe7, 0xda, 0x54, 0x8a, 0xcd, 0x24, 0xd8, 0x84, 0x68, 0xb4, 0xe0, 0xb9, 0xf4, 0xd0, 0x7e, + 0x87, 0x86, 0x2d, 0xc7, 0x23, 0xc5, 0xd1, 0x7b, 0x84, 0x72, 0x58, 0xc1, 0x9d, 0xd1, 0xcf, 0x6d, + 0x3a, 0x76, 0x06, 0xbe, 0xe7, 0x78, 0xb6, 0xff, 0xa0, 0x60, 0xf3, 0x8c, 0x67, 0xf0, 0xaf, 0xf9, + 0x8a, 0x98, 0x62, 0x31, 0xdd, 0xe9, 0xd7, 0x61, 0x81, 0xc5, 0x84, 0x0e, 0x15, 0x3f, 0x88, 0xb0, + 0x63, 0x0c, 0x2a, 0x72, 0x64, 0x3a, 0xcc, 0xfc, 0x40, 0xbc, 0x09, 0x07, 0x49, 0x14, 0x39, 0x4d, + 0x8f, 0xda, 0x52, 0x57, 0x69, 0x64, 0x5d, 0xdd, 0x43, 0x93, 0xeb, 0x32, 0xef, 0x21, 0xd6, 0x5b, + 0x8a, 0xc6, 0xd7, 0x10, 0x1c, 0xe9, 0xab, 0x24, 0xdd, 0x39, 0x48, 0x09, 0xe3, 0x3a, 0x94, 0x23, + 0x6b, 0x87, 0xda, 0x6d, 0x97, 0xca, 0x1a, 0x92, 0x94, 0xd9, 0x6f, 0x76, 0x3b, 0x59, 0x7d, 0x91, + 0x46, 0x52, 0x19, 0x1f, 0x03, 0x68, 0x11, 0xaf, 0x4d, 0x5c, 0x0e, 0x61, 0x9a, 0x43, 0x50, 0x5a, + 0x8c, 0x25, 0xd0, 0xfb, 0x51, 0x47, 0xd4, 0x66, 0xfe, 0x8d, 0xe0, 0x80, 0x0c, 0xaa, 0x62, 0x75, + 0x57, 0xe0, 0xa0, 0xe2, 0x86, 0x5b, 0xd9, 0x42, 0x77, 0x37, 0x0f, 0x09, 0x98, 0x92, 0x25, 0x53, + 0xf9, 0xa2, 0x74, 0x27, 0x57, 0x56, 0x1e, 0x39, 0xdf, 0xa1, 0x09, 0x9d, 0x1f, 0xbf, 0x0a, 0xda, + 0x4d, 0xe2, 0x91, 0x26, 0xb5, 0xd3, 0x69, 0xa7, 0x14, 0xfb, 0xb2, 0x5a, 0x64, 0x18, 0xfb, 0x4a, + 0x9f, 0x1e, 0xb5, 0x9c, 0xed, 0x6d, 0x59, 0xb0, 0x08, 0xa1, 0xbc, 0xe9, 0x78, 0xbb, 0xec, 0xde, + 0xcb, 0x66, 0x1c, 0x3b, 0xb1, 0x2b, 0xbd, 0x9b, 0x08, 0xf8, 0x10, 0x4c, 0xb5, 0x43, 0x57, 0x30, + 0x80, 0x7d, 0xe2, 0x65, 0xa8, 0xda, 0x34, 0xb2, 0x42, 0x27, 0x10, 0xeb, 0xcf, 0x8b, 0xb4, 0x4a, + 0x13, 0x5b, 0x07, 0xc7, 0xf2, 0xbd, 0x0d, 0x97, 0x44, 0x91, 0x4c, 0x40, 0x69, 0x83, 0xf1, 0x2a, + 0x2c, 0x30, 0x9b, 0xd9, 0x34, 0x4f, 0xe7, 0xa7, 0x79, 0x24, 0x07, 0x5f, 0xc2, 0x93, 0x88, 0x09, + 0x3c, 0xc3, 0xf2, 0xfe, 0xc5, 0x20, 0x10, 0x4a, 0x46, 0x3c, 0x0e, 0x4d, 0xf5, 0xcb, 0x9f, 0x7d, + 0x6b, 0x9c, 0x8d, 0xbf, 0x1f, 0x07, 0xac, 0xee, 0x13, 0x1a, 0x76, 0x1c, 0x8b, 0xe2, 0xef, 0x20, + 0x98, 0x66, 0xa6, 0xf1, 0xf3, 0x83, 0xb6, 0x25, 0xe7, 0xab, 0x3e, 0xb9, 0x8b, 0x30, 0xb3, 0x66, + 0x2c, 0xbd, 0xf5, 0xb7, 0x7f, 0x7e, 0xb7, 0xb4, 0x88, 0x9f, 0xe5, 0x2f, 0x4a, 0x9d, 0x73, 0xea, + 0xeb, 0x4e, 0x84, 0xdf, 0x46, 0x80, 0xc5, 0x39, 0x48, 0xa9, 0xd9, 0xe3, 0xd3, 0x83, 0x20, 0xf6, + 0xa9, 0xed, 0xeb, 0xcf, 0x2b, 0x59, 0xa5, 0x66, 0xf9, 0x21, 0x65, 0x39, 0x84, 0x77, 0xe0, 0x00, + 0x56, 0x39, 0x80, 0x13, 0xd8, 0xe8, 0x07, 0xa0, 0xfe, 0x90, 0x79, 0xf4, 0x51, 0x9d, 0x26, 0x76, + 0xdf, 0x45, 0x30, 0x73, 0x8f, 0xdf, 0x21, 0x86, 0x38, 0x69, 0x6b, 0x62, 0x4e, 0xe2, 0xe6, 0x38, + 0x5a, 0xe3, 0x38, 0x47, 0xfa, 0x3c, 0x3e, 0x2a, 0x91, 0x46, 0x71, 0x48, 0x49, 0x2b, 0x07, 0xf8, + 0x2c, 0xc2, 0xef, 0x21, 0x98, 0x4d, 0x8a, 0xbe, 0xf8, 0xe4, 0x20, 0x94, 0xb9, 0xa2, 0xb0, 0x3e, + 0xb9, 0x0a, 0xaa, 0xf1, 0x12, 0xc7, 0x78, 0xdc, 0xe8, 0xbb, 0x9c, 0xeb, 0xb9, 0xfa, 0xea, 0x3b, + 0x08, 0xa6, 0xae, 0xd1, 0xa1, 0x7c, 0x9b, 0x20, 0xb8, 0x1e, 0x07, 0xf6, 0x59, 0x6a, 0xfc, 0x13, + 0x04, 0xcf, 0x5d, 0xa3, 0x71, 0xff, 0xf4, 0x88, 0x57, 0x86, 0xe7, 0x2c, 0x41, 0xbb, 0xd3, 0x23, + 0xf4, 0x4c, 0xf3, 0x42, 0x9d, 0x23, 0x7b, 0x09, 0x9f, 0x2a, 0x22, 0x61, 0xb4, 0xe7, 0x59, 0x0f, + 0x04, 0x8e, 0x3f, 0x21, 0x38, 0xd4, 0xfd, 0xb6, 0x86, 0xf3, 0x09, 0xb5, 0xef, 0xd3, 0x9b, 0x7e, + 0x6b, 0xdc, 0x28, 0x9b, 0x57, 0x6a, 0x5c, 0xe4, 0xc8, 0x5f, 0xc1, 0x2f, 0x17, 0x21, 0x97, 0x65, + 0xdf, 0xa8, 0xfe, 0x50, 0x7e, 0x3e, 0xe2, 0xef, 0xc0, 0x1c, 0xf6, 0x9f, 0x11, 0x3c, 0x2b, 0xf5, + 0x6e, 0xec, 0x90, 0x30, 0xbe, 0x4c, 0xd9, 0x19, 0x3a, 0x1a, 0x69, 0x3e, 0x63, 0x66, 0x0d, 0xd5, + 0x9e, 0x71, 0x85, 0xcf, 0xe5, 0x53, 0xf8, 0xb5, 0x7d, 0xcf, 0xc5, 0x62, 0x6a, 0x6c, 0x01, 0xfb, + 0x2d, 0x04, 0xf3, 0xd7, 0x68, 0x7c, 0x33, 0xad, 0xe2, 0x9e, 0x1c, 0xe9, 0x65, 0x48, 0x5f, 0xaa, + 0x29, 0xcf, 0xcf, 0xf2, 0xa7, 0x94, 0x22, 0x6b, 0x1c, 0xdc, 0x29, 0x7c, 0xb2, 0x08, 0x5c, 0x56, + 0x39, 0x7e, 0x17, 0xc1, 0x11, 0x15, 0x44, 0xf6, 0xa2, 0xf6, 0x89, 0xfd, 0xbd, 0x53, 0x89, 0xd7, + 0xae, 0x21, 0xe8, 0x1a, 0x1c, 0xdd, 0x19, 0xa3, 0x3f, 0x81, 0x5b, 0x3d, 0x28, 0xd6, 0xd1, 0xea, + 0x0a, 0xc2, 0xbf, 0x47, 0x30, 0x9b, 0x14, 0x63, 0x07, 0xfb, 0x28, 0xf7, 0x02, 0x34, 0xc9, 0x68, + 0x20, 0x56, 0x5b, 0x3f, 0xdb, 0xdf, 0xa1, 0xea, 0x78, 0x49, 0xd5, 0x1a, 0xf7, 0x72, 0x3e, 0x8c, + 0xbd, 0x8f, 0x00, 0xb2, 0x82, 0x32, 0x7e, 0xa9, 0x78, 0x1e, 0x4a, 0xd1, 0x59, 0x9f, 0x6c, 0x49, + 0xd9, 0xa8, 0xf1, 0xf9, 0xac, 0xe8, 0xcb, 0x85, 0x31, 0x24, 0xa0, 0xd6, 0x7a, 0x52, 0x7c, 0xfe, + 0x31, 0x82, 0x19, 0x5e, 0xc7, 0xc3, 0x27, 0x06, 0x61, 0x56, 0xcb, 0x7c, 0x93, 0x74, 0xfd, 0x8b, + 0x1c, 0xea, 0x72, 0xa3, 0x28, 0x10, 0xaf, 0xa3, 0x55, 0xdc, 0x81, 0xd9, 0xa4, 0x72, 0x36, 0x98, + 0x1e, 0xb9, 0xca, 0x9a, 0xbe, 0x5c, 0x70, 0x30, 0x48, 0x88, 0x2a, 0x72, 0xc0, 0xea, 0xb0, 0x1c, + 0x30, 0xcd, 0xc2, 0x34, 0x3e, 0x5e, 0x14, 0xc4, 0xff, 0x0f, 0x8e, 0x39, 0xcd, 0xd1, 0x9d, 0x34, + 0x96, 0x87, 0xe5, 0x01, 0xe6, 0x9d, 0xef, 0x21, 0x38, 0xd4, 0x7d, 0xb8, 0xc6, 0x47, 0xbb, 0x62, + 0xa6, 0x7a, 0xd7, 0xd0, 0xf3, 0x5e, 0x1c, 0x74, 0x30, 0x37, 0x3e, 0xcd, 0x51, 0xac, 0xe3, 0x0b, + 0x43, 0x77, 0xc6, 0x2d, 0x19, 0x75, 0x98, 0xa2, 0xb5, 0xec, 0x55, 0xeb, 0xd7, 0x08, 0xe6, 0xa5, + 0xde, 0x3b, 0x21, 0xa5, 0xc5, 0xb0, 0x26, 0xb7, 0x11, 0x98, 0x2d, 0xe3, 0x55, 0x0e, 0xff, 0x93, + 0xf8, 0xfc, 0x88, 0xf0, 0x25, 0xec, 0xb5, 0x98, 0x21, 0xfd, 0x03, 0x82, 0xc3, 0xf7, 0x12, 0xde, + 0x7f, 0x48, 0xf8, 0x37, 0x38, 0xfe, 0xd7, 0xf0, 0x2b, 0x05, 0xe7, 0xbc, 0x61, 0xd3, 0x38, 0x8b, + 0xf0, 0x2f, 0x11, 0x94, 0xe5, 0xab, 0x0a, 0x3e, 0x35, 0x70, 0x63, 0xe4, 0xdf, 0x5d, 0x26, 0x49, + 0x66, 0x71, 0xa8, 0x31, 0x4e, 0x14, 0xa6, 0x53, 0x61, 0x9f, 0x11, 0xfa, 0x1d, 0x04, 0x38, 0xbd, + 0x33, 0xa7, 0xb7, 0x68, 0xfc, 0x62, 0xce, 0xd4, 0xc0, 0xc2, 0x8c, 0x7e, 0x6a, 0x68, 0xbf, 0x7c, + 0x2a, 0x5d, 0x2d, 0x4c, 0xa5, 0x7e, 0x6a, 0xff, 0x9b, 0x08, 0xaa, 0xd7, 0x68, 0x7a, 0x07, 0x29, + 0xf0, 0x65, 0xfe, 0x51, 0x48, 0x5f, 0x19, 0xde, 0x51, 0x20, 0x3a, 0xc3, 0x11, 0xbd, 0x88, 0x8b, + 0x5d, 0x25, 0x01, 0xfc, 0x00, 0xc1, 0xc2, 0x6d, 0x95, 0xa2, 0xf8, 0xcc, 0x30, 0x4b, 0xb9, 0x48, + 0x3e, 0x3a, 0xae, 0x8f, 0x73, 0x5c, 0x6b, 0xc6, 0x48, 0xb8, 0xd6, 0xc5, 0xfb, 0xca, 0x0f, 0x51, + 0x72, 0x89, 0xed, 0xaa, 0x67, 0xff, 0xaf, 0x7e, 0x2b, 0x28, 0x8b, 0x1b, 0xe7, 0x39, 0xbe, 0x1a, + 0x3e, 0x33, 0x0a, 0xbe, 0xba, 0x28, 0x72, 0xe3, 0xef, 0x23, 0x38, 0xcc, 0xdf, 0x1a, 0x54, 0xc5, + 0x5d, 0x29, 0x66, 0xd0, 0xcb, 0xc4, 0x08, 0x29, 0x46, 0xc4, 0x1f, 0x63, 0x5f, 0xa0, 0xd6, 0xe5, + 0x3b, 0xc2, 0xb7, 0x10, 0x1c, 0x90, 0x49, 0x4d, 0xac, 0xee, 0xda, 0x30, 0xc7, 0xed, 0x37, 0x09, + 0x0a, 0xba, 0xad, 0x8e, 0x46, 0xb7, 0xf7, 0x10, 0xcc, 0x89, 0x6a, 0x7e, 0xc1, 0x51, 0x41, 0x29, + 0xf7, 0xeb, 0x5d, 0x35, 0x0e, 0x51, 0x0c, 0x36, 0xbe, 0xc8, 0xcd, 0xde, 0xc5, 0xf5, 0x22, 0xb3, + 0x81, 0x6f, 0x47, 0xf5, 0x87, 0xa2, 0x12, 0xfb, 0xa8, 0xee, 0xfa, 0xcd, 0xe8, 0x0d, 0x03, 0x17, + 0x26, 0x44, 0xd6, 0xe7, 0x2c, 0xc2, 0x31, 0x54, 0x18, 0x39, 0x78, 0xe1, 0x04, 0x2f, 0x77, 0x95, + 0x59, 0x7a, 0x6a, 0x2a, 0xba, 0xde, 0x53, 0x88, 0xc9, 0x32, 0xa0, 0xb8, 0xc6, 0xe2, 0x17, 0x0a, + 0xcd, 0x72, 0x43, 0x6f, 0x23, 0x38, 0xac, 0xb2, 0x3d, 0x31, 0x3f, 0x32, 0xd7, 0x8b, 0x50, 0x88, + 0x43, 0x35, 0x5e, 0x1d, 0x89, 0x48, 0x1c, 0xce, 0xa5, 0xab, 0x7f, 0x7c, 0x72, 0x0c, 0xfd, 0xe5, + 0xc9, 0x31, 0xf4, 0x8f, 0x27, 0xc7, 0xd0, 0x1b, 0x17, 0x46, 0xfb, 0x4f, 0xad, 0xe5, 0x3a, 0xd4, + 0x8b, 0x55, 0xf5, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x30, 0xc0, 0x40, 0x7a, 0x39, 0x2c, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2818,6 +2989,8 @@ type ApplicationServiceClient interface { GetApplicationSyncWindows(ctx context.Context, in *ApplicationSyncWindowsQuery, opts ...grpc.CallOption) (*ApplicationSyncWindowsResponse, error) // Get the meta-data (author, date, tags, message) for a specific revision of the application RevisionMetadata(ctx context.Context, in *RevisionMetadataQuery, opts ...grpc.CallOption) (*v1alpha1.RevisionMetadata, error) + // Get the chart metadata (description, maintainers, home) for a specific revision of the application + RevisionChartDetails(ctx context.Context, in *RevisionMetadataQuery, opts ...grpc.CallOption) (*v1alpha1.ChartDetails, error) // GetManifests returns application manifests GetManifests(ctx context.Context, in *ApplicationManifestQuery, opts ...grpc.CallOption) (*apiclient.ManifestResponse, error) // GetManifestsWithFiles returns application manifests using provided files to generate them @@ -2954,6 +3127,15 @@ func (c *applicationServiceClient) RevisionMetadata(ctx context.Context, in *Rev return out, nil } +func (c *applicationServiceClient) RevisionChartDetails(ctx context.Context, in *RevisionMetadataQuery, opts ...grpc.CallOption) (*v1alpha1.ChartDetails, error) { + out := new(v1alpha1.ChartDetails) + err := c.cc.Invoke(ctx, "/application.ApplicationService/RevisionChartDetails", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *applicationServiceClient) GetManifests(ctx context.Context, in *ApplicationManifestQuery, opts ...grpc.CallOption) (*apiclient.ManifestResponse, error) { out := new(apiclient.ManifestResponse) err := c.cc.Invoke(ctx, "/application.ApplicationService/GetManifests", in, out, opts...) @@ -3221,6 +3403,8 @@ type ApplicationServiceServer interface { GetApplicationSyncWindows(context.Context, *ApplicationSyncWindowsQuery) (*ApplicationSyncWindowsResponse, error) // Get the meta-data (author, date, tags, message) for a specific revision of the application RevisionMetadata(context.Context, *RevisionMetadataQuery) (*v1alpha1.RevisionMetadata, error) + // Get the chart metadata (description, maintainers, home) for a specific revision of the application + RevisionChartDetails(context.Context, *RevisionMetadataQuery) (*v1alpha1.ChartDetails, error) // GetManifests returns application manifests GetManifests(context.Context, *ApplicationManifestQuery) (*apiclient.ManifestResponse, error) // GetManifestsWithFiles returns application manifests using provided files to generate them @@ -3288,6 +3472,9 @@ func (*UnimplementedApplicationServiceServer) GetApplicationSyncWindows(ctx cont func (*UnimplementedApplicationServiceServer) RevisionMetadata(ctx context.Context, req *RevisionMetadataQuery) (*v1alpha1.RevisionMetadata, error) { return nil, status.Errorf(codes.Unimplemented, "method RevisionMetadata not implemented") } +func (*UnimplementedApplicationServiceServer) RevisionChartDetails(ctx context.Context, req *RevisionMetadataQuery) (*v1alpha1.ChartDetails, error) { + return nil, status.Errorf(codes.Unimplemented, "method RevisionChartDetails not implemented") +} func (*UnimplementedApplicationServiceServer) GetManifests(ctx context.Context, req *ApplicationManifestQuery) (*apiclient.ManifestResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetManifests not implemented") } @@ -3482,6 +3669,24 @@ func _ApplicationService_RevisionMetadata_Handler(srv interface{}, ctx context.C return interceptor(ctx, in, info, handler) } +func _ApplicationService_RevisionChartDetails_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RevisionMetadataQuery) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ApplicationServiceServer).RevisionChartDetails(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/application.ApplicationService/RevisionChartDetails", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ApplicationServiceServer).RevisionChartDetails(ctx, req.(*RevisionMetadataQuery)) + } + return interceptor(ctx, in, info, handler) +} + func _ApplicationService_GetManifests_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ApplicationManifestQuery) if err := dec(in); err != nil { @@ -3884,6 +4089,10 @@ var _ApplicationService_serviceDesc = grpc.ServiceDesc{ MethodName: "RevisionMetadata", Handler: _ApplicationService_RevisionMetadata_Handler, }, + { + MethodName: "RevisionChartDetails", + Handler: _ApplicationService_RevisionChartDetails_Handler, + }, { MethodName: "GetManifests", Handler: _ApplicationService_GetManifests_Handler, @@ -4002,6 +4211,15 @@ func (m *ApplicationQuery) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.Project) > 0 { + for iNdEx := len(m.Project) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Project[iNdEx]) + copy(dAtA[i:], m.Project[iNdEx]) + i = encodeVarintApplication(dAtA, i, uint64(len(m.Project[iNdEx]))) + i-- + dAtA[i] = 0x42 + } + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -4121,6 +4339,13 @@ func (m *RevisionMetadataQuery) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x22 + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -4173,6 +4398,13 @@ func (m *ApplicationResourceEventsQuery) MarshalToSizedBuffer(dAtA []byte) (int, i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x32 + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -4237,6 +4469,13 @@ func (m *ApplicationManifestQuery) MarshalToSizedBuffer(dAtA []byte) (int, error i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x22 + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -4323,6 +4562,13 @@ func (m *ApplicationManifestQueryWithFiles) MarshalToSizedBuffer(dAtA []byte) (i i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x22 + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -4541,6 +4787,13 @@ func (m *ApplicationUpdateRequest) MarshalToSizedBuffer(dAtA []byte) (int, error i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x1a + } if m.Validate != nil { i-- if *m.Validate { @@ -4592,6 +4845,13 @@ func (m *ApplicationDeleteRequest) MarshalToSizedBuffer(dAtA []byte) (int, error i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x2a + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -4688,6 +4948,13 @@ func (m *ApplicationSyncRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x6a + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -4831,6 +5098,13 @@ func (m *ApplicationUpdateSpecRequest) MarshalToSizedBuffer(dAtA []byte) (int, e i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x2a + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -4898,6 +5172,13 @@ func (m *ApplicationPatchRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x32 + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -4959,6 +5240,13 @@ func (m *ApplicationRollbackRequest) MarshalToSizedBuffer(dAtA []byte) (int, err i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x3a + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -5029,6 +5317,13 @@ func (m *ApplicationResourceRequest) MarshalToSizedBuffer(dAtA []byte) (int, err i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x42 + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -5113,6 +5408,13 @@ func (m *ApplicationResourcePatchRequest) MarshalToSizedBuffer(dAtA []byte) (int i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x52 + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -5215,6 +5517,13 @@ func (m *ApplicationResourceDeleteRequest) MarshalToSizedBuffer(dAtA []byte) (in i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x52 + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -5319,6 +5628,13 @@ func (m *ResourceActionRunRequest) MarshalToSizedBuffer(dAtA []byte) (int, error i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x4a + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -5489,6 +5805,15 @@ func (m *ApplicationPodLogsQuery) MarshalToSizedBuffer(dAtA []byte) (int, error) i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -5710,6 +6035,13 @@ func (m *OperationTerminateRequest) MarshalToSizedBuffer(dAtA []byte) (int, erro i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x1a + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -5753,6 +6085,13 @@ func (m *ApplicationSyncWindowsQuery) MarshalToSizedBuffer(dAtA []byte) (int, er i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x1a + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -5956,6 +6295,13 @@ func (m *ResourcesQuery) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x42 + } if m.AppNamespace != nil { i -= len(*m.AppNamespace) copy(dAtA[i:], *m.AppNamespace) @@ -6175,6 +6521,13 @@ func (m *ListAppLinksRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.Project != nil { + i -= len(*m.Project) + copy(dAtA[i:], *m.Project) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Project))) + i-- + dAtA[i] = 0x22 + } if m.Namespace != nil { i -= len(*m.Namespace) copy(dAtA[i:], *m.Namespace) @@ -6241,6 +6594,12 @@ func (m *ApplicationQuery) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if len(m.Project) > 0 { + for _, s := range m.Project { + l = len(s) + n += 1 + l + sovApplication(uint64(l)) + } + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6285,6 +6644,10 @@ func (m *RevisionMetadataQuery) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6317,6 +6680,10 @@ func (m *ApplicationResourceEventsQuery) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6341,6 +6708,10 @@ func (m *ApplicationManifestQuery) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6381,6 +6752,10 @@ func (m *ApplicationManifestQueryWithFiles) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6473,6 +6848,10 @@ func (m *ApplicationUpdateRequest) Size() (n int) { if m.Validate != nil { n += 2 } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6500,6 +6879,10 @@ func (m *ApplicationDeleteRequest) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6578,6 +6961,10 @@ func (m *ApplicationSyncRequest) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6605,6 +6992,10 @@ func (m *ApplicationUpdateSpecRequest) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6633,6 +7024,10 @@ func (m *ApplicationPatchRequest) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6662,6 +7057,10 @@ func (m *ApplicationRollbackRequest) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6702,6 +7101,10 @@ func (m *ApplicationResourceRequest) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6750,6 +7153,10 @@ func (m *ApplicationResourcePatchRequest) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6796,6 +7203,10 @@ func (m *ApplicationResourceDeleteRequest) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6840,6 +7251,10 @@ func (m *ResourceActionRunRequest) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6942,6 +7357,10 @@ func (m *ApplicationPodLogsQuery) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 2 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -6993,6 +7412,10 @@ func (m *OperationTerminateRequest) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -7013,6 +7436,10 @@ func (m *ApplicationSyncWindowsQuery) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -7119,6 +7546,10 @@ func (m *ResourcesQuery) Size() (n int) { l = len(*m.AppNamespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -7203,6 +7634,10 @@ func (m *ListAppLinksRequest) Size() (n int) { l = len(*m.Namespace) n += 1 + l + sovApplication(uint64(l)) } + if m.Project != nil { + l = len(*m.Project) + n += 1 + l + sovApplication(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -7474,6 +7909,38 @@ func (m *ApplicationQuery) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Project = append(m.Project, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -7744,24 +8211,57 @@ func (m *RevisionMetadataQuery) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipApplication(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthApplication - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) } - m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - if hasFields[0]&uint64(0x00000001) == 0 { - return github_com_gogo_protobuf_proto.NewRequiredNotSetError("name") + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipApplication(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthApplication + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("name") } if hasFields[0]&uint64(0x00000002) == 0 { return github_com_gogo_protobuf_proto.NewRequiredNotSetError("revision") @@ -7968,6 +8468,39 @@ func (m *ApplicationResourceEventsQuery) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -8123,6 +8656,39 @@ func (m *ApplicationManifestQuery) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -8369,6 +8935,39 @@ func (m *ApplicationManifestQueryWithFiles) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -8791,6 +9390,39 @@ func (m *ApplicationUpdateRequest) Unmarshal(dAtA []byte) error { } b := bool(v != 0) m.Validate = &b + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -8967,6 +9599,39 @@ func (m *ApplicationDeleteRequest) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -9455,6 +10120,39 @@ func (m *ApplicationSyncRequest) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -9635,6 +10333,39 @@ func (m *ApplicationUpdateSpecRequest) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -9828,6 +10559,39 @@ func (m *ApplicationPatchRequest) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -10019,6 +10783,39 @@ func (m *ApplicationRollbackRequest) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -10247,7 +11044,41 @@ func (m *ApplicationResourceRequest) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Kind = &s + iNdEx = postIndex + hasFields[0] |= uint64(0x00000008) + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppNamespace", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -10276,12 +11107,11 @@ func (m *ApplicationResourceRequest) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } s := string(dAtA[iNdEx:postIndex]) - m.Kind = &s + m.AppNamespace = &s iNdEx = postIndex - hasFields[0] |= uint64(0x00000008) - case 7: + case 8: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AppNamespace", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -10310,7 +11140,7 @@ func (m *ApplicationResourceRequest) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } s := string(dAtA[iNdEx:postIndex]) - m.AppNamespace = &s + m.Project = &s iNdEx = postIndex default: iNdEx = preIndex @@ -10679,6 +11509,39 @@ func (m *ApplicationResourcePatchRequest) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -11026,6 +11889,39 @@ func (m *ApplicationResourceDeleteRequest) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -11359,6 +12255,39 @@ func (m *ResourceActionRunRequest) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -12049,6 +12978,39 @@ func (m *ApplicationPodLogsQuery) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -12399,6 +13361,39 @@ func (m *OperationTerminateRequest) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -12521,6 +13516,39 @@ func (m *ApplicationSyncWindowsQuery) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -13192,6 +14220,39 @@ func (m *ResourcesQuery) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.AppNamespace = &s iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) @@ -13676,6 +14737,39 @@ func (m *ListAppLinksRequest) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.Namespace = &s iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + 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 ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Project = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) diff --git a/pkg/apiclient/application/application.pb.gw.go b/pkg/apiclient/application/application.pb.gw.go index 80c86e4fc9a19..ed6064cadb9a2 100644 --- a/pkg/apiclient/application/application.pb.gw.go +++ b/pkg/apiclient/application/application.pb.gw.go @@ -459,6 +459,100 @@ func local_request_ApplicationService_RevisionMetadata_0(ctx context.Context, ma } +var ( + filter_ApplicationService_RevisionChartDetails_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0, "revision": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} +) + +func request_ApplicationService_RevisionChartDetails_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RevisionMetadataQuery + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + + protoReq.Name, err = runtime.StringP(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) + } + + val, ok = pathParams["revision"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "revision") + } + + protoReq.Revision, err = runtime.StringP(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "revision", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_RevisionChartDetails_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.RevisionChartDetails(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_ApplicationService_RevisionChartDetails_0(ctx context.Context, marshaler runtime.Marshaler, server ApplicationServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RevisionMetadataQuery + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["name"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name") + } + + protoReq.Name, err = runtime.StringP(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) + } + + val, ok = pathParams["revision"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "revision") + } + + protoReq.Revision, err = runtime.StringP(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "revision", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_RevisionChartDetails_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.RevisionChartDetails(ctx, &protoReq) + return msg, metadata, err + +} + var ( filter_ApplicationService_GetManifests_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} ) @@ -2085,6 +2179,29 @@ func RegisterApplicationServiceHandlerServer(ctx context.Context, mux *runtime.S }) + mux.Handle("GET", pattern_ApplicationService_RevisionChartDetails_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ApplicationService_RevisionChartDetails_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ApplicationService_RevisionChartDetails_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_ApplicationService_GetManifests_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -2685,6 +2802,26 @@ func RegisterApplicationServiceHandlerClient(ctx context.Context, mux *runtime.S }) + mux.Handle("GET", pattern_ApplicationService_RevisionChartDetails_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ApplicationService_RevisionChartDetails_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ApplicationService_RevisionChartDetails_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_ApplicationService_GetManifests_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -3123,6 +3260,8 @@ var ( pattern_ApplicationService_RevisionMetadata_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"api", "v1", "applications", "name", "revisions", "revision", "metadata"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_ApplicationService_RevisionChartDetails_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"api", "v1", "applications", "name", "revisions", "revision", "chartdetails"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_ApplicationService_GetManifests_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "name", "manifests"}, "", runtime.AssumeColonVerbOpt(true))) pattern_ApplicationService_GetManifestsWithFiles_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "applications", "manifestsWithFiles"}, "", runtime.AssumeColonVerbOpt(true))) @@ -3181,6 +3320,8 @@ var ( forward_ApplicationService_RevisionMetadata_0 = runtime.ForwardResponseMessage + forward_ApplicationService_RevisionChartDetails_0 = runtime.ForwardResponseMessage + forward_ApplicationService_GetManifests_0 = runtime.ForwardResponseMessage forward_ApplicationService_GetManifestsWithFiles_0 = runtime.ForwardResponseMessage diff --git a/pkg/apiclient/applicationset/applicationset.pb.go b/pkg/apiclient/applicationset/applicationset.pb.go index f24e802789c2d..8f717d1f6920f 100644 --- a/pkg/apiclient/applicationset/applicationset.pb.go +++ b/pkg/apiclient/applicationset/applicationset.pb.go @@ -35,7 +35,9 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // ApplicationSetGetQuery is a query for applicationset resources type ApplicationSetGetQuery struct { // the applicationsets's name - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The application set namespace. Default empty is argocd control plane namespace + AppsetNamespace string `protobuf:"bytes,2,opt,name=appsetNamespace,proto3" json:"appsetNamespace,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -81,11 +83,20 @@ func (m *ApplicationSetGetQuery) GetName() string { return "" } +func (m *ApplicationSetGetQuery) GetAppsetNamespace() string { + if m != nil { + return m.AppsetNamespace + } + return "" +} + type ApplicationSetListQuery struct { // the project names to restrict returned list applicationsets Projects []string `protobuf:"bytes,1,rep,name=projects,proto3" json:"projects,omitempty"` // the selector to restrict returned list to applications only with matched labels - Selector string `protobuf:"bytes,2,opt,name=selector,proto3" json:"selector,omitempty"` + Selector string `protobuf:"bytes,2,opt,name=selector,proto3" json:"selector,omitempty"` + // The application set namespace. Default empty is argocd control plane namespace + AppsetNamespace string `protobuf:"bytes,3,opt,name=appsetNamespace,proto3" json:"appsetNamespace,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -138,6 +149,13 @@ func (m *ApplicationSetListQuery) GetSelector() string { return "" } +func (m *ApplicationSetListQuery) GetAppsetNamespace() string { + if m != nil { + return m.AppsetNamespace + } + return "" +} + type ApplicationSetResponse struct { Project string `protobuf:"bytes,1,opt,name=project,proto3" json:"project,omitempty"` Applicationset *v1alpha1.ApplicationSet `protobuf:"bytes,2,opt,name=applicationset,proto3" json:"applicationset,omitempty"` @@ -249,7 +267,9 @@ func (m *ApplicationSetCreateRequest) GetUpsert() bool { } type ApplicationSetDeleteRequest struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The application set namespace. Default empty is argocd control plane namespace + AppsetNamespace string `protobuf:"bytes,2,opt,name=appsetNamespace,proto3" json:"appsetNamespace,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -295,6 +315,13 @@ func (m *ApplicationSetDeleteRequest) GetName() string { return "" } +func (m *ApplicationSetDeleteRequest) GetAppsetNamespace() string { + if m != nil { + return m.AppsetNamespace + } + return "" +} + func init() { proto.RegisterType((*ApplicationSetGetQuery)(nil), "applicationset.ApplicationSetGetQuery") proto.RegisterType((*ApplicationSetListQuery)(nil), "applicationset.ApplicationSetListQuery") @@ -308,39 +335,40 @@ func init() { } var fileDescriptor_eacb9df0ce5738fa = []byte{ - // 501 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x94, 0xcf, 0x6e, 0x13, 0x31, - 0x10, 0xc6, 0xe5, 0xb6, 0x84, 0xd6, 0x48, 0x1c, 0x2c, 0xd1, 0x86, 0x05, 0x85, 0x68, 0x0f, 0xa5, - 0x14, 0xb0, 0x95, 0x70, 0x83, 0x13, 0x7f, 0xa4, 0x0a, 0x29, 0x07, 0xba, 0xbd, 0x71, 0x41, 0xae, - 0x33, 0xda, 0x2e, 0xdd, 0xae, 0x8d, 0xed, 0xac, 0x84, 0x10, 0x17, 0x24, 0x9e, 0x80, 0x27, 0x00, - 0x2e, 0x48, 0x5c, 0x79, 0x08, 0x8e, 0x48, 0xbc, 0x00, 0x8a, 0x78, 0x10, 0x64, 0x6f, 0x36, 0xe9, - 0x5a, 0x69, 0xc3, 0x21, 0xbd, 0x79, 0xd6, 0xe3, 0xf1, 0x6f, 0x3f, 0x7f, 0x33, 0x78, 0xd7, 0x80, - 0x2e, 0x41, 0x33, 0xae, 0x54, 0x9e, 0x09, 0x6e, 0x33, 0x59, 0x18, 0xb0, 0x41, 0x48, 0x95, 0x96, - 0x56, 0x92, 0xab, 0xcd, 0xaf, 0xd1, 0xcd, 0x54, 0xca, 0x34, 0x07, 0xc6, 0x55, 0xc6, 0x78, 0x51, - 0x48, 0x5b, 0xed, 0x54, 0xd9, 0xd1, 0x20, 0xcd, 0xec, 0xd1, 0xe8, 0x90, 0x0a, 0x79, 0xc2, 0xb8, - 0x4e, 0xa5, 0xd2, 0xf2, 0xb5, 0x5f, 0xdc, 0x17, 0x43, 0x56, 0xf6, 0x99, 0x3a, 0x4e, 0xdd, 0x49, - 0x73, 0xfa, 0x2e, 0x56, 0xf6, 0x78, 0xae, 0x8e, 0x78, 0x8f, 0xa5, 0x50, 0x80, 0xe6, 0x16, 0x86, - 0x55, 0xb5, 0xf8, 0x1e, 0xde, 0x7c, 0x3c, 0xcb, 0x3b, 0x00, 0xbb, 0x07, 0x76, 0x7f, 0x04, 0xfa, - 0x2d, 0x21, 0x78, 0xad, 0xe0, 0x27, 0xd0, 0x46, 0x5d, 0xb4, 0xb3, 0x91, 0xf8, 0x75, 0xbc, 0x8f, - 0xb7, 0x9a, 0xd9, 0x83, 0xcc, 0x4c, 0xd2, 0x23, 0xbc, 0xee, 0x48, 0x40, 0x58, 0xd3, 0x46, 0xdd, - 0xd5, 0x9d, 0x8d, 0x64, 0x1a, 0xbb, 0x3d, 0x03, 0x39, 0x08, 0x2b, 0x75, 0x7b, 0xc5, 0x97, 0x9b, - 0xc6, 0xf1, 0x37, 0x14, 0x12, 0x24, 0x60, 0x94, 0x13, 0x82, 0xb4, 0xf1, 0xe5, 0x49, 0x89, 0x09, - 0x44, 0x1d, 0x12, 0x8b, 0x03, 0xcd, 0x7c, 0xd9, 0x2b, 0xfd, 0x01, 0x9d, 0x89, 0x43, 0x6b, 0x71, - 0xfc, 0xe2, 0x95, 0x18, 0xd2, 0xb2, 0x4f, 0xd5, 0x71, 0x4a, 0x9d, 0x38, 0xf4, 0xd4, 0x71, 0x5a, - 0x8b, 0x43, 0x03, 0x8e, 0xe0, 0x8e, 0xf8, 0x3b, 0xc2, 0x37, 0x9a, 0x29, 0x4f, 0x35, 0x70, 0x0b, - 0x09, 0xbc, 0x19, 0x81, 0x99, 0x47, 0x85, 0x2e, 0x9e, 0x8a, 0x6c, 0xe2, 0xd6, 0x48, 0x19, 0xd0, - 0x95, 0x06, 0xeb, 0xc9, 0x24, 0x8a, 0x7b, 0x21, 0xec, 0x33, 0xc8, 0x61, 0x06, 0x3b, 0xe7, 0x79, - 0xfb, 0x9f, 0x2f, 0xe1, 0x6b, 0xcd, 0x33, 0x07, 0xa0, 0xcb, 0x4c, 0x00, 0xf9, 0x8a, 0xf0, 0xea, - 0x1e, 0x58, 0xb2, 0x4d, 0x03, 0x07, 0xcf, 0x37, 0x4f, 0xb4, 0xd4, 0x5f, 0x8e, 0xb7, 0x3f, 0xfc, - 0xfe, 0xfb, 0x69, 0xa5, 0x4b, 0x3a, 0xbe, 0x25, 0xca, 0x5e, 0xd0, 0x46, 0x86, 0xbd, 0x73, 0xf8, - 0xef, 0xc9, 0x17, 0x84, 0xd7, 0x9c, 0x23, 0xc9, 0xed, 0xf3, 0x31, 0xa7, 0xae, 0x8d, 0x5e, 0x2c, - 0x93, 0xd3, 0x95, 0x8d, 0x6f, 0x79, 0xd6, 0xeb, 0x64, 0xeb, 0x0c, 0x56, 0xf2, 0x03, 0xe1, 0x56, - 0xe5, 0x1b, 0x72, 0xf7, 0x7c, 0xcc, 0x86, 0xbb, 0x96, 0x2c, 0x29, 0xf3, 0x98, 0x77, 0xe2, 0xb3, - 0x30, 0x1f, 0x86, 0x36, 0xfb, 0x88, 0x70, 0xab, 0x72, 0xd0, 0x22, 0xec, 0x86, 0xcf, 0xa2, 0x05, - 0x8e, 0xa9, 0x9b, 0xbd, 0x7e, 0xe3, 0xdd, 0x05, 0x6f, 0xfc, 0xe4, 0xf9, 0xcf, 0x71, 0x07, 0xfd, - 0x1a, 0x77, 0xd0, 0x9f, 0x71, 0x07, 0xbd, 0x7c, 0xf4, 0x7f, 0xc3, 0x50, 0xe4, 0x19, 0x14, 0xe1, - 0xf4, 0x3d, 0x6c, 0xf9, 0x11, 0xf8, 0xe0, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb1, 0x22, 0xb1, - 0x96, 0xac, 0x05, 0x00, 0x00, + // 526 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x94, 0xdf, 0x8a, 0x13, 0x31, + 0x14, 0xc6, 0xc9, 0x76, 0xad, 0xbb, 0x11, 0x14, 0x02, 0xee, 0xd6, 0x51, 0x6a, 0x99, 0x8b, 0xb5, + 0xae, 0x98, 0xd0, 0x7a, 0xa7, 0x57, 0xfe, 0x81, 0x45, 0x28, 0xa2, 0xb3, 0xe0, 0x85, 0x5e, 0x48, + 0x76, 0x7a, 0x98, 0x1d, 0x77, 0x3a, 0x89, 0x49, 0x3a, 0x20, 0x8b, 0x37, 0x82, 0x4f, 0xe0, 0x13, + 0xa8, 0x37, 0x82, 0xb7, 0x3e, 0x84, 0x97, 0x82, 0x2f, 0x20, 0xc5, 0x07, 0x91, 0xc9, 0xcc, 0xb4, + 0x3b, 0xa1, 0xdb, 0x0a, 0x76, 0xef, 0x72, 0x26, 0x99, 0x73, 0x7e, 0xf9, 0xf2, 0x9d, 0x83, 0x77, + 0x35, 0xa8, 0x0c, 0x14, 0xe3, 0x52, 0x26, 0x71, 0xc8, 0x4d, 0x2c, 0x52, 0x0d, 0xc6, 0x09, 0xa9, + 0x54, 0xc2, 0x08, 0x72, 0xb1, 0xfe, 0xd5, 0xbb, 0x16, 0x09, 0x11, 0x25, 0xc0, 0xb8, 0x8c, 0x19, + 0x4f, 0x53, 0x61, 0x8a, 0x9d, 0xe2, 0xb4, 0x37, 0x88, 0x62, 0x73, 0x38, 0x3e, 0xa0, 0xa1, 0x18, + 0x31, 0xae, 0x22, 0x21, 0x95, 0x78, 0x6d, 0x17, 0xb7, 0xc3, 0x21, 0xcb, 0xfa, 0x4c, 0x1e, 0x45, + 0xf9, 0x9f, 0xfa, 0x64, 0x2d, 0x96, 0xf5, 0x78, 0x22, 0x0f, 0x79, 0x8f, 0x45, 0x90, 0x82, 0xe2, + 0x06, 0x86, 0x45, 0x36, 0xff, 0x39, 0xde, 0xba, 0x3f, 0x3b, 0xb7, 0x0f, 0x66, 0x0f, 0xcc, 0xb3, + 0x31, 0xa8, 0xb7, 0x84, 0xe0, 0xf5, 0x94, 0x8f, 0xa0, 0x85, 0x3a, 0xa8, 0xbb, 0x19, 0xd8, 0x35, + 0xe9, 0xe2, 0x4b, 0x5c, 0x4a, 0x0d, 0xe6, 0x09, 0x1f, 0x81, 0x96, 0x3c, 0x84, 0xd6, 0x9a, 0xdd, + 0x76, 0x3f, 0xfb, 0xc7, 0x78, 0xbb, 0x9e, 0x77, 0x10, 0xeb, 0x32, 0xb1, 0x87, 0x37, 0x72, 0x66, + 0x08, 0x8d, 0x6e, 0xa1, 0x4e, 0xa3, 0xbb, 0x19, 0x4c, 0xe3, 0x7c, 0x4f, 0x43, 0x02, 0xa1, 0x11, + 0xaa, 0xcc, 0x3c, 0x8d, 0xe7, 0x15, 0x6f, 0xcc, 0x2f, 0xfe, 0x15, 0xb9, 0xb7, 0x0a, 0x40, 0xcb, + 0x5c, 0x5c, 0xd2, 0xc2, 0xe7, 0xcb, 0x62, 0xe5, 0xc5, 0xaa, 0x90, 0x18, 0xec, 0xbc, 0x83, 0x05, + 0xb8, 0xd0, 0x1f, 0xd0, 0x99, 0xe0, 0xb4, 0x12, 0xdc, 0x2e, 0x5e, 0x85, 0x43, 0x9a, 0xf5, 0xa9, + 0x3c, 0x8a, 0x68, 0x2e, 0x38, 0x3d, 0xf1, 0x3b, 0xad, 0x04, 0xa7, 0x0e, 0x87, 0x53, 0xc3, 0xff, + 0x86, 0xf0, 0xd5, 0xfa, 0x91, 0x87, 0x0a, 0xb8, 0x81, 0x00, 0xde, 0x8c, 0x41, 0xcf, 0xa3, 0x42, + 0x67, 0x4f, 0x45, 0xb6, 0x70, 0x73, 0x2c, 0x35, 0xa8, 0x42, 0x83, 0x8d, 0xa0, 0x8c, 0xfc, 0x97, + 0x2e, 0xec, 0x23, 0x48, 0x60, 0x06, 0xfb, 0x5f, 0x96, 0xe9, 0x7f, 0x3a, 0x87, 0x2f, 0xd7, 0xb3, + 0xef, 0x83, 0xca, 0xe2, 0x10, 0xc8, 0x17, 0x84, 0x1b, 0x7b, 0x60, 0xc8, 0x0e, 0x75, 0xfa, 0x67, + 0xbe, 0x75, 0xbd, 0x95, 0x8a, 0xe3, 0xef, 0xbc, 0xff, 0xf5, 0xe7, 0xe3, 0x5a, 0x87, 0xb4, 0x6d, + 0x43, 0x66, 0x3d, 0xa7, 0x89, 0x35, 0x3b, 0xce, 0x2f, 0xfa, 0x8e, 0x7c, 0x46, 0x78, 0x3d, 0x77, + 0x39, 0xb9, 0xb1, 0x18, 0x73, 0xda, 0x09, 0xde, 0xd3, 0x55, 0x72, 0xe6, 0x69, 0xfd, 0xeb, 0x96, + 0xf5, 0x0a, 0xd9, 0x3e, 0x85, 0x95, 0x7c, 0x47, 0xb8, 0x59, 0x38, 0x8c, 0xdc, 0x5a, 0x8c, 0x59, + 0xf3, 0xe1, 0x8a, 0x25, 0x65, 0x16, 0xf3, 0xa6, 0x7f, 0x1a, 0xe6, 0x5d, 0xd7, 0x90, 0x1f, 0x10, + 0x6e, 0x16, 0x5e, 0x5b, 0x86, 0x5d, 0x73, 0xa4, 0xb7, 0xc4, 0x31, 0xd5, 0x58, 0xa8, 0xde, 0x78, + 0x77, 0xc9, 0x1b, 0x3f, 0x78, 0xfc, 0x63, 0xd2, 0x46, 0x3f, 0x27, 0x6d, 0xf4, 0x7b, 0xd2, 0x46, + 0x2f, 0xee, 0xfd, 0xdb, 0x28, 0x0e, 0x93, 0x18, 0x52, 0x77, 0xf6, 0x1f, 0x34, 0xed, 0x00, 0xbe, + 0xf3, 0x37, 0x00, 0x00, 0xff, 0xff, 0x96, 0x3f, 0x16, 0xa7, 0x2a, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -563,6 +591,13 @@ func (m *ApplicationSetGetQuery) MarshalToSizedBuffer(dAtA []byte) (int, error) i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.AppsetNamespace) > 0 { + i -= len(m.AppsetNamespace) + copy(dAtA[i:], m.AppsetNamespace) + i = encodeVarintApplicationset(dAtA, i, uint64(len(m.AppsetNamespace))) + i-- + dAtA[i] = 0x12 + } if len(m.Name) > 0 { i -= len(m.Name) copy(dAtA[i:], m.Name) @@ -597,6 +632,13 @@ func (m *ApplicationSetListQuery) MarshalToSizedBuffer(dAtA []byte) (int, error) i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.AppsetNamespace) > 0 { + i -= len(m.AppsetNamespace) + copy(dAtA[i:], m.AppsetNamespace) + i = encodeVarintApplicationset(dAtA, i, uint64(len(m.AppsetNamespace))) + i-- + dAtA[i] = 0x1a + } if len(m.Selector) > 0 { i -= len(m.Selector) copy(dAtA[i:], m.Selector) @@ -735,6 +777,13 @@ func (m *ApplicationSetDeleteRequest) MarshalToSizedBuffer(dAtA []byte) (int, er i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.AppsetNamespace) > 0 { + i -= len(m.AppsetNamespace) + copy(dAtA[i:], m.AppsetNamespace) + i = encodeVarintApplicationset(dAtA, i, uint64(len(m.AppsetNamespace))) + i-- + dAtA[i] = 0x12 + } if len(m.Name) > 0 { i -= len(m.Name) copy(dAtA[i:], m.Name) @@ -766,6 +815,10 @@ func (m *ApplicationSetGetQuery) Size() (n int) { if l > 0 { n += 1 + l + sovApplicationset(uint64(l)) } + l = len(m.AppsetNamespace) + if l > 0 { + n += 1 + l + sovApplicationset(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -788,6 +841,10 @@ func (m *ApplicationSetListQuery) Size() (n int) { if l > 0 { n += 1 + l + sovApplicationset(uint64(l)) } + l = len(m.AppsetNamespace) + if l > 0 { + n += 1 + l + sovApplicationset(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -843,6 +900,10 @@ func (m *ApplicationSetDeleteRequest) Size() (n int) { if l > 0 { n += 1 + l + sovApplicationset(uint64(l)) } + l = len(m.AppsetNamespace) + if l > 0 { + n += 1 + l + sovApplicationset(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -916,6 +977,38 @@ func (m *ApplicationSetGetQuery) Unmarshal(dAtA []byte) error { } m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppsetNamespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplicationset + } + 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 ErrInvalidLengthApplicationset + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplicationset + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AppsetNamespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplicationset(dAtA[iNdEx:]) @@ -1031,6 +1124,38 @@ func (m *ApplicationSetListQuery) Unmarshal(dAtA []byte) error { } m.Selector = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppsetNamespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplicationset + } + 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 ErrInvalidLengthApplicationset + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplicationset + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AppsetNamespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplicationset(dAtA[iNdEx:]) @@ -1340,6 +1465,38 @@ func (m *ApplicationSetDeleteRequest) Unmarshal(dAtA []byte) error { } m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppsetNamespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplicationset + } + 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 ErrInvalidLengthApplicationset + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplicationset + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AppsetNamespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplicationset(dAtA[iNdEx:]) diff --git a/pkg/apiclient/applicationset/applicationset.pb.gw.go b/pkg/apiclient/applicationset/applicationset.pb.gw.go index db537f548cb30..5e4c73f7add3b 100644 --- a/pkg/apiclient/applicationset/applicationset.pb.gw.go +++ b/pkg/apiclient/applicationset/applicationset.pb.gw.go @@ -33,6 +33,10 @@ var _ = utilities.NewDoubleArray var _ = descriptor.ForMessage var _ = metadata.Join +var ( + filter_ApplicationSetService_Get_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + func request_ApplicationSetService_Get_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationSetServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq ApplicationSetGetQuery var metadata runtime.ServerMetadata @@ -55,6 +59,13 @@ func request_ApplicationSetService_Get_0(ctx context.Context, marshaler runtime. return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationSetService_Get_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.Get(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -82,6 +93,13 @@ func local_request_ApplicationSetService_Get_0(ctx context.Context, marshaler ru return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationSetService_Get_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.Get(ctx, &protoReq) return msg, metadata, err @@ -175,6 +193,10 @@ func local_request_ApplicationSetService_Create_0(ctx context.Context, marshaler } +var ( + filter_ApplicationSetService_Delete_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + func request_ApplicationSetService_Delete_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationSetServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq ApplicationSetDeleteRequest var metadata runtime.ServerMetadata @@ -197,6 +219,13 @@ func request_ApplicationSetService_Delete_0(ctx context.Context, marshaler runti return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationSetService_Delete_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.Delete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -224,6 +253,13 @@ func local_request_ApplicationSetService_Delete_0(ctx context.Context, marshaler return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationSetService_Delete_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.Delete(ctx, &protoReq) return msg, metadata, err diff --git a/pkg/apiclient/grpcproxy.go b/pkg/apiclient/grpcproxy.go index 9e5b841ae273a..72fea42efee3f 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 { @@ -124,14 +131,14 @@ func (c *client) startGRPCProxy() (*grpc.Server, net.Listener, error) { } md, _ := metadata.FromIncomingContext(stream.Context()) + headersMD, err := parseGRPCHeaders(c.Headers) - for _, kv := range c.Headers { - if len(strings.Split(kv, ":"))%2 == 1 { - return fmt.Errorf("additional headers key/values must be separated by a colon(:): %s", kv) - } - md.Append(strings.Split(kv, ":")[0], strings.Split(kv, ":")[1]) + if err != nil { + return err } + md = metadata.Join(md, headersMD) + resp, err := c.executeRequest(fullMethodName, msg, md) if err != nil { return err @@ -209,3 +216,16 @@ func (c *client) useGRPCProxy() (net.Addr, io.Closer, error) { return nil }), nil } + +func parseGRPCHeaders(headerStrings []string) (metadata.MD, error) { + md := metadata.New(map[string]string{}) + for _, kv := range headerStrings { + i := strings.IndexByte(kv, ':') + // zero means meaningless empty header name + if i <= 0 { + return nil, fmt.Errorf("additional headers must be colon(:)-separated: %s", kv) + } + md.Append(kv[0:i], kv[i+1:]) + } + return md, nil +} diff --git a/pkg/apiclient/repository/repository.pb.go b/pkg/apiclient/repository/repository.pb.go index b70b3ab1b9585..5540580c21f45 100644 --- a/pkg/apiclient/repository/repository.pb.go +++ b/pkg/apiclient/repository/repository.pb.go @@ -366,7 +366,9 @@ type RepoAccessQuery struct { // Reference between project and repository that allow you automatically to be added as item inside SourceRepos project entity Project string `protobuf:"bytes,17,opt,name=project,proto3" json:"project,omitempty"` // Google Cloud Platform service account key - GcpServiceAccountKey string `protobuf:"bytes,18,opt,name=gcpServiceAccountKey,proto3" json:"gcpServiceAccountKey,omitempty"` + GcpServiceAccountKey string `protobuf:"bytes,18,opt,name=gcpServiceAccountKey,proto3" json:"gcpServiceAccountKey,omitempty"` + // Whether to force HTTP basic auth + ForceHttpBasicAuth bool `protobuf:"varint,19,opt,name=forceHttpBasicAuth,proto3" json:"forceHttpBasicAuth,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -524,6 +526,13 @@ func (m *RepoAccessQuery) GetGcpServiceAccountKey() string { return "" } +func (m *RepoAccessQuery) GetForceHttpBasicAuth() bool { + if m != nil { + return m.ForceHttpBasicAuth + } + return false +} + type RepoResponse struct { XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` @@ -694,78 +703,79 @@ func init() { } var fileDescriptor_8d38260443475705 = []byte{ - // 1127 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0xcd, 0x6e, 0x1c, 0x45, - 0x10, 0xd6, 0xd8, 0xce, 0xda, 0x2e, 0xff, 0x64, 0xdd, 0x36, 0x61, 0xd8, 0x38, 0x8e, 0x35, 0x09, - 0x91, 0xb1, 0xc2, 0x4c, 0xbc, 0x08, 0x81, 0x82, 0x40, 0x72, 0x6c, 0x2b, 0xb1, 0xb0, 0x70, 0x98, - 0xc8, 0x1c, 0x10, 0x08, 0xb5, 0x67, 0xcb, 0xbb, 0x93, 0xcc, 0xce, 0x74, 0xba, 0x7b, 0x17, 0x56, - 0x51, 0x2e, 0x9c, 0x90, 0xe0, 0x82, 0x10, 0x12, 0x37, 0x2e, 0x48, 0x1c, 0x78, 0x01, 0x1e, 0x81, - 0x23, 0x12, 0x2f, 0x80, 0x2c, 0x5e, 0x80, 0x17, 0x40, 0xa8, 0xbb, 0x67, 0x67, 0x66, 0xbd, 0x3f, - 0x76, 0x84, 0xf1, 0xad, 0xeb, 0xab, 0x9a, 0xaa, 0xaf, 0xbf, 0xae, 0xae, 0xde, 0x05, 0x47, 0x20, - 0x6f, 0x23, 0xf7, 0x38, 0xb2, 0x44, 0x84, 0x32, 0xe1, 0x9d, 0xc2, 0xd2, 0x65, 0x3c, 0x91, 0x09, - 0x81, 0x1c, 0xa9, 0x2c, 0xd7, 0x93, 0xa4, 0x1e, 0xa1, 0x47, 0x59, 0xe8, 0xd1, 0x38, 0x4e, 0x24, - 0x95, 0x61, 0x12, 0x0b, 0x13, 0x59, 0xd9, 0xab, 0x87, 0xb2, 0xd1, 0x3a, 0x74, 0x83, 0xa4, 0xe9, - 0x51, 0x5e, 0x4f, 0x18, 0x4f, 0x1e, 0xeb, 0xc5, 0xeb, 0x41, 0xcd, 0x6b, 0x57, 0x3d, 0xf6, 0xa4, - 0xae, 0xbe, 0x14, 0x1e, 0x65, 0x2c, 0x0a, 0x03, 0xfd, 0xad, 0xd7, 0xde, 0xa0, 0x11, 0x6b, 0xd0, - 0x0d, 0xaf, 0x8e, 0x31, 0x72, 0x2a, 0xb1, 0x96, 0x66, 0xdb, 0x39, 0x25, 0x9b, 0xa6, 0x75, 0x2a, - 0x7d, 0xa7, 0x03, 0x73, 0x3e, 0xb2, 0x64, 0x93, 0x31, 0xf1, 0x61, 0x0b, 0x79, 0x87, 0x10, 0x98, - 0x50, 0x41, 0xb6, 0xb5, 0x6a, 0xad, 0x4d, 0xfb, 0x7a, 0x4d, 0x2a, 0x30, 0xc5, 0xb1, 0x1d, 0x8a, - 0x30, 0x89, 0xed, 0x31, 0x8d, 0x67, 0x36, 0xb1, 0x61, 0x92, 0x32, 0xf6, 0x01, 0x6d, 0xa2, 0x3d, - 0xae, 0x5d, 0x5d, 0x93, 0xac, 0x00, 0x50, 0xc6, 0x1e, 0xf2, 0xe4, 0x31, 0x06, 0xd2, 0x9e, 0xd0, - 0xce, 0x02, 0xe2, 0x6c, 0xc0, 0xe4, 0x26, 0x63, 0xbb, 0xf1, 0x51, 0xa2, 0x8a, 0xca, 0x0e, 0xc3, - 0x6e, 0x51, 0xb5, 0x56, 0x18, 0xa3, 0xb2, 0x91, 0x16, 0xd4, 0x6b, 0xe7, 0x57, 0x0b, 0x16, 0x53, - 0xba, 0xdb, 0x28, 0x69, 0x18, 0xa5, 0xa4, 0xeb, 0x50, 0x12, 0x49, 0x8b, 0x07, 0x26, 0xc3, 0x4c, - 0x75, 0xdf, 0xcd, 0xd5, 0x71, 0xbb, 0xea, 0xe8, 0xc5, 0x67, 0x41, 0xcd, 0x6d, 0x57, 0x5d, 0xf6, - 0xa4, 0xee, 0x2a, 0xad, 0xdd, 0x82, 0xd6, 0x6e, 0x57, 0x6b, 0x77, 0x33, 0x07, 0x1f, 0xe9, 0xb4, - 0x7e, 0x9a, 0xbe, 0xb8, 0xdb, 0xb1, 0x51, 0xbb, 0x1d, 0xef, 0xdb, 0xed, 0xbb, 0x50, 0xee, 0x0a, - 0xed, 0xa3, 0x60, 0x49, 0x2c, 0x90, 0xbc, 0x06, 0x97, 0x42, 0x89, 0x4d, 0x61, 0x5b, 0xab, 0xe3, - 0x6b, 0x33, 0xd5, 0x45, 0xb7, 0x70, 0x3c, 0xa9, 0x34, 0xbe, 0x89, 0x70, 0xb6, 0x60, 0x5a, 0x7d, - 0x3e, 0xfc, 0x8c, 0x1c, 0x98, 0x3d, 0x4a, 0x14, 0x55, 0x3c, 0xe2, 0x28, 0x8c, 0x6c, 0x53, 0x7e, - 0x0f, 0xe6, 0xfc, 0x3d, 0x01, 0x97, 0x35, 0x89, 0x20, 0x40, 0x31, 0xfa, 0xbc, 0x5b, 0x02, 0x79, - 0x9c, 0x6f, 0x33, 0xb3, 0x95, 0x8f, 0x51, 0x21, 0x3e, 0x4f, 0x78, 0x2d, 0xdd, 0x65, 0x66, 0x93, - 0x9b, 0x30, 0x27, 0x44, 0xe3, 0x21, 0x0f, 0xdb, 0x54, 0xe2, 0xfb, 0xd8, 0x49, 0x0f, 0xbd, 0x17, - 0x54, 0x19, 0xc2, 0x58, 0x60, 0xd0, 0xe2, 0x68, 0x5f, 0xd2, 0x2c, 0x33, 0x9b, 0xdc, 0x86, 0x05, - 0x19, 0x89, 0xad, 0x28, 0xc4, 0x58, 0x6e, 0x21, 0x97, 0xdb, 0x54, 0x52, 0xbb, 0xa4, 0xb3, 0xf4, - 0x3b, 0xc8, 0x3a, 0x94, 0x7b, 0x40, 0x55, 0x72, 0x52, 0x07, 0xf7, 0xe1, 0x59, 0x8b, 0x4d, 0xf7, - 0xb6, 0x98, 0xde, 0x23, 0x18, 0x4c, 0xef, 0x6f, 0x19, 0xa6, 0x31, 0xa6, 0x87, 0x11, 0xee, 0x07, - 0xa1, 0x3d, 0xa3, 0xe9, 0xe5, 0x00, 0xb9, 0x03, 0x8b, 0xa6, 0xb3, 0x36, 0xd5, 0xc9, 0x66, 0xfb, - 0x9c, 0xd5, 0x09, 0x06, 0xb9, 0xc8, 0x2a, 0xcc, 0x64, 0xf0, 0xee, 0xb6, 0x3d, 0xb7, 0x6a, 0xad, - 0x8d, 0xfb, 0x45, 0x88, 0xbc, 0x0d, 0x2f, 0xe7, 0x66, 0x2c, 0x24, 0x8d, 0x22, 0xdd, 0x7a, 0xbb, - 0xdb, 0xf6, 0xbc, 0x8e, 0x1e, 0xe6, 0x26, 0xef, 0x41, 0x25, 0x73, 0xed, 0xc4, 0x12, 0x39, 0xe3, - 0xa1, 0xc0, 0x7b, 0x54, 0xe0, 0x01, 0x8f, 0xec, 0xcb, 0x9a, 0xd4, 0x88, 0x08, 0xb2, 0x04, 0x97, - 0x18, 0x4f, 0xbe, 0xe8, 0xd8, 0x65, 0x1d, 0x6a, 0x0c, 0xd5, 0xe3, 0x2c, 0x6d, 0xe3, 0x05, 0xd3, - 0xe3, 0xa9, 0x49, 0xaa, 0xb0, 0x54, 0x0f, 0xd8, 0x23, 0xe4, 0xed, 0x30, 0xc0, 0xcd, 0x20, 0x48, - 0x5a, 0xb1, 0xd6, 0x9c, 0xe8, 0xb0, 0x81, 0x3e, 0x67, 0x1e, 0x66, 0x55, 0xcb, 0x75, 0x7b, 0xde, - 0xf9, 0xd9, 0x82, 0x05, 0x05, 0x6c, 0x71, 0xa4, 0x12, 0x7d, 0x7c, 0xda, 0x42, 0x21, 0xc9, 0x27, - 0x85, 0x2e, 0x9c, 0xa9, 0x3e, 0xf8, 0x6f, 0xd7, 0xd7, 0xcf, 0x6e, 0x51, 0xda, 0xcf, 0x57, 0xa0, - 0xd4, 0x62, 0x02, 0xb9, 0x4c, 0x6f, 0x45, 0x6a, 0xa9, 0xb3, 0x0e, 0x38, 0xd6, 0xc4, 0x7e, 0x1c, - 0x75, 0x74, 0x33, 0x4f, 0xf9, 0x39, 0xe0, 0x3c, 0x35, 0x44, 0x0f, 0x58, 0xed, 0xa2, 0x88, 0x56, - 0xff, 0x99, 0x37, 0x35, 0x0d, 0x98, 0x8a, 0x49, 0xbe, 0xb1, 0x60, 0x62, 0x2f, 0x14, 0x92, 0xbc, - 0x54, 0x1c, 0x10, 0xd9, 0x38, 0xa8, 0xec, 0x9d, 0x17, 0x0b, 0x55, 0xc4, 0xb9, 0xfe, 0xe5, 0x1f, - 0x7f, 0x7d, 0x37, 0x76, 0x85, 0x2c, 0xe9, 0x67, 0xac, 0xbd, 0x91, 0xbf, 0x19, 0x21, 0x8a, 0xaf, - 0xc6, 0x2c, 0xf2, 0xb5, 0x05, 0xe3, 0xf7, 0x71, 0x28, 0x9b, 0x73, 0xd3, 0xc4, 0xb9, 0xa1, 0x99, - 0x5c, 0x23, 0x57, 0x07, 0x31, 0xf1, 0x9e, 0x29, 0xeb, 0x39, 0xf9, 0xde, 0x82, 0xb2, 0xe2, 0xed, - 0x17, 0x7c, 0x17, 0x23, 0xd4, 0xf2, 0x28, 0xa1, 0xc8, 0xa7, 0x30, 0x65, 0x68, 0x1d, 0x0d, 0xa5, - 0x53, 0xee, 0x85, 0x8f, 0x84, 0xb3, 0xa6, 0x53, 0x3a, 0x64, 0x75, 0xc4, 0x8e, 0x3d, 0xae, 0x52, - 0x36, 0x4d, 0x7a, 0xf5, 0x9c, 0x90, 0x57, 0x4e, 0xa6, 0xcf, 0x5e, 0xf3, 0xca, 0xf2, 0x20, 0x57, - 0x76, 0x17, 0xcf, 0x54, 0x8e, 0xaa, 0x12, 0xdf, 0x5a, 0x30, 0x77, 0x1f, 0x65, 0xfe, 0xee, 0x92, - 0xeb, 0x03, 0x32, 0x17, 0xdf, 0xe4, 0x8a, 0x33, 0x3c, 0x20, 0x23, 0xf0, 0x8e, 0x26, 0xf0, 0xa6, - 0x73, 0x67, 0x30, 0x01, 0xf3, 0xe8, 0xea, 0x3c, 0x07, 0xfe, 0x9e, 0xa6, 0x52, 0x33, 0x19, 0xee, - 0x5a, 0xeb, 0xa4, 0xad, 0x29, 0x3d, 0xc0, 0xa8, 0xb9, 0xd5, 0xa0, 0x5c, 0x0e, 0x95, 0x79, 0xa5, - 0x08, 0xe7, 0xe1, 0x19, 0x09, 0x57, 0x93, 0x58, 0x23, 0xb7, 0x46, 0xa9, 0xd0, 0xc0, 0xa8, 0x19, - 0x98, 0x32, 0x3f, 0x58, 0x50, 0x32, 0xd3, 0x8b, 0x5c, 0x3b, 0x59, 0xb1, 0x67, 0xaa, 0x9d, 0xe3, - 0x55, 0x78, 0x55, 0x73, 0x5c, 0x76, 0x06, 0xf6, 0xda, 0x5d, 0x3d, 0x3c, 0xd4, 0xd5, 0xfc, 0xd1, - 0x82, 0x72, 0x97, 0x42, 0xf7, 0xdb, 0x8b, 0x23, 0xe9, 0x9c, 0x4e, 0x92, 0xfc, 0x64, 0x41, 0xc9, - 0x4c, 0xd4, 0x7e, 0x5e, 0x3d, 0x93, 0xf6, 0x1c, 0x79, 0x6d, 0x98, 0x03, 0xae, 0x8c, 0x68, 0x73, - 0x4d, 0xe5, 0x79, 0x2e, 0xe4, 0x2f, 0x16, 0x94, 0xbb, 0x74, 0x86, 0x0b, 0xf9, 0x7f, 0x11, 0x76, - 0x5f, 0x8c, 0x30, 0xa1, 0x50, 0xda, 0xc6, 0x08, 0x25, 0x0e, 0xbb, 0x02, 0xf6, 0x49, 0x38, 0x6b, - 0xfe, 0x5b, 0x66, 0xc6, 0xae, 0x8f, 0x9a, 0xb1, 0x4a, 0x90, 0x06, 0x94, 0x4d, 0x89, 0x82, 0x1e, - 0x2f, 0x5c, 0xec, 0xc6, 0x19, 0x8a, 0x91, 0x67, 0x30, 0xff, 0x11, 0x8d, 0x42, 0xa5, 0xac, 0xf9, - 0x9d, 0x4a, 0xae, 0xf6, 0x4d, 0x92, 0xfc, 0xf7, 0xeb, 0x88, 0x6a, 0x55, 0x5d, 0xed, 0xb6, 0x73, - 0x73, 0xd4, 0xbd, 0x6e, 0xa7, 0xa5, 0x8c, 0x92, 0xf7, 0x76, 0x7e, 0x3b, 0x5e, 0xb1, 0x7e, 0x3f, - 0x5e, 0xb1, 0xfe, 0x3c, 0x5e, 0xb1, 0x3e, 0x7e, 0xeb, 0x6c, 0xff, 0xd8, 0x02, 0xfd, 0x43, 0xb3, - 0xf0, 0xdf, 0xea, 0xb0, 0xa4, 0xff, 0x5c, 0xbd, 0xf1, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x89, - 0x56, 0x9b, 0x65, 0x41, 0x0e, 0x00, 0x00, + // 1146 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x57, 0x5f, 0x6f, 0x1b, 0x45, + 0x10, 0xd7, 0x25, 0x8d, 0x9b, 0x4c, 0x9a, 0xd4, 0xd9, 0x84, 0x72, 0xb8, 0x69, 0x1a, 0x5d, 0x4b, + 0x15, 0xa2, 0x72, 0xd7, 0x18, 0x21, 0x50, 0x11, 0x48, 0xce, 0x1f, 0x35, 0x11, 0x11, 0x29, 0x57, + 0x85, 0x07, 0x04, 0x42, 0x9b, 0xf3, 0xc4, 0xbe, 0xf6, 0x7c, 0xb7, 0xdd, 0x5d, 0x1b, 0xac, 0xaa, + 0x2f, 0x3c, 0x21, 0xc1, 0x0b, 0x42, 0x48, 0xbc, 0x21, 0x24, 0x24, 0x1e, 0xf8, 0x02, 0x7c, 0x04, + 0x1e, 0x91, 0xf8, 0x02, 0x28, 0xe2, 0x73, 0x20, 0xb4, 0xbb, 0xe7, 0xbb, 0x73, 0x62, 0x3b, 0xa9, + 0x08, 0x79, 0xdb, 0xf9, 0xcd, 0xdc, 0xcc, 0x6f, 0x7f, 0x3b, 0x3b, 0x6b, 0x83, 0x23, 0x90, 0x77, + 0x90, 0x7b, 0x1c, 0x59, 0x22, 0x42, 0x99, 0xf0, 0x6e, 0x61, 0xe9, 0x32, 0x9e, 0xc8, 0x84, 0x40, + 0x8e, 0x54, 0x16, 0x1b, 0x49, 0xd2, 0x88, 0xd0, 0xa3, 0x2c, 0xf4, 0x68, 0x1c, 0x27, 0x92, 0xca, + 0x30, 0x89, 0x85, 0x89, 0xac, 0xec, 0x36, 0x42, 0xd9, 0x6c, 0x1f, 0xb8, 0x41, 0xd2, 0xf2, 0x28, + 0x6f, 0x24, 0x8c, 0x27, 0x8f, 0xf5, 0xe2, 0xf5, 0xa0, 0xee, 0x75, 0xaa, 0x1e, 0x7b, 0xd2, 0x50, + 0x5f, 0x0a, 0x8f, 0x32, 0x16, 0x85, 0x81, 0xfe, 0xd6, 0xeb, 0xac, 0xd1, 0x88, 0x35, 0xe9, 0x9a, + 0xd7, 0xc0, 0x18, 0x39, 0x95, 0x58, 0x4f, 0xb3, 0x6d, 0x9d, 0x92, 0x4d, 0xd3, 0x3a, 0x95, 0xbe, + 0xd3, 0x85, 0x19, 0x1f, 0x59, 0x52, 0x63, 0x4c, 0x7c, 0xd8, 0x46, 0xde, 0x25, 0x04, 0x2e, 0xa9, + 0x20, 0xdb, 0x5a, 0xb6, 0x56, 0xa6, 0x7c, 0xbd, 0x26, 0x15, 0x98, 0xe4, 0xd8, 0x09, 0x45, 0x98, + 0xc4, 0xf6, 0x98, 0xc6, 0x33, 0x9b, 0xd8, 0x70, 0x99, 0x32, 0xf6, 0x01, 0x6d, 0xa1, 0x3d, 0xae, + 0x5d, 0x3d, 0x93, 0x2c, 0x01, 0x50, 0xc6, 0x1e, 0xf2, 0xe4, 0x31, 0x06, 0xd2, 0xbe, 0xa4, 0x9d, + 0x05, 0xc4, 0x59, 0x83, 0xcb, 0x35, 0xc6, 0x76, 0xe2, 0xc3, 0x44, 0x15, 0x95, 0x5d, 0x86, 0xbd, + 0xa2, 0x6a, 0xad, 0x30, 0x46, 0x65, 0x33, 0x2d, 0xa8, 0xd7, 0xce, 0x6f, 0x16, 0xcc, 0xa7, 0x74, + 0x37, 0x51, 0xd2, 0x30, 0x4a, 0x49, 0x37, 0xa0, 0x24, 0x92, 0x36, 0x0f, 0x4c, 0x86, 0xe9, 0xea, + 0x9e, 0x9b, 0xab, 0xe3, 0xf6, 0xd4, 0xd1, 0x8b, 0xcf, 0x82, 0xba, 0xdb, 0xa9, 0xba, 0xec, 0x49, + 0xc3, 0x55, 0x5a, 0xbb, 0x05, 0xad, 0xdd, 0x9e, 0xd6, 0x6e, 0x2d, 0x07, 0x1f, 0xe9, 0xb4, 0x7e, + 0x9a, 0xbe, 0xb8, 0xdb, 0xb1, 0x51, 0xbb, 0x1d, 0x3f, 0xb1, 0xdb, 0x77, 0xa1, 0xdc, 0x13, 0xda, + 0x47, 0xc1, 0x92, 0x58, 0x20, 0x79, 0x0d, 0x26, 0x42, 0x89, 0x2d, 0x61, 0x5b, 0xcb, 0xe3, 0x2b, + 0xd3, 0xd5, 0x79, 0xb7, 0x70, 0x3c, 0xa9, 0x34, 0xbe, 0x89, 0x70, 0x36, 0x60, 0x4a, 0x7d, 0x3e, + 0xfc, 0x8c, 0x1c, 0xb8, 0x72, 0x98, 0x28, 0xaa, 0x78, 0xc8, 0x51, 0x18, 0xd9, 0x26, 0xfd, 0x3e, + 0xcc, 0xf9, 0x69, 0x02, 0xae, 0x6a, 0x12, 0x41, 0x80, 0x62, 0xf4, 0x79, 0xb7, 0x05, 0xf2, 0x38, + 0xdf, 0x66, 0x66, 0x2b, 0x1f, 0xa3, 0x42, 0x7c, 0x9e, 0xf0, 0x7a, 0xba, 0xcb, 0xcc, 0x26, 0xb7, + 0x61, 0x46, 0x88, 0xe6, 0x43, 0x1e, 0x76, 0xa8, 0xc4, 0xf7, 0xb1, 0x9b, 0x1e, 0x7a, 0x3f, 0xa8, + 0x32, 0x84, 0xb1, 0xc0, 0xa0, 0xcd, 0xd1, 0x9e, 0xd0, 0x2c, 0x33, 0x9b, 0xdc, 0x85, 0x39, 0x19, + 0x89, 0x8d, 0x28, 0xc4, 0x58, 0x6e, 0x20, 0x97, 0x9b, 0x54, 0x52, 0xbb, 0xa4, 0xb3, 0x9c, 0x74, + 0x90, 0x55, 0x28, 0xf7, 0x81, 0xaa, 0xe4, 0x65, 0x1d, 0x7c, 0x02, 0xcf, 0x5a, 0x6c, 0xaa, 0xbf, + 0xc5, 0xf4, 0x1e, 0xc1, 0x60, 0x7a, 0x7f, 0x8b, 0x30, 0x85, 0x31, 0x3d, 0x88, 0x70, 0x2f, 0x08, + 0xed, 0x69, 0x4d, 0x2f, 0x07, 0xc8, 0x3d, 0x98, 0x37, 0x9d, 0x55, 0x53, 0x27, 0x9b, 0xed, 0xf3, + 0x8a, 0x4e, 0x30, 0xc8, 0x45, 0x96, 0x61, 0x3a, 0x83, 0x77, 0x36, 0xed, 0x99, 0x65, 0x6b, 0x65, + 0xdc, 0x2f, 0x42, 0xe4, 0x6d, 0x78, 0x39, 0x37, 0x63, 0x21, 0x69, 0x14, 0xe9, 0xd6, 0xdb, 0xd9, + 0xb4, 0x67, 0x75, 0xf4, 0x30, 0x37, 0x79, 0x0f, 0x2a, 0x99, 0x6b, 0x2b, 0x96, 0xc8, 0x19, 0x0f, + 0x05, 0xae, 0x53, 0x81, 0xfb, 0x3c, 0xb2, 0xaf, 0x6a, 0x52, 0x23, 0x22, 0xc8, 0x02, 0x4c, 0x30, + 0x9e, 0x7c, 0xd1, 0xb5, 0xcb, 0x3a, 0xd4, 0x18, 0xaa, 0xc7, 0x59, 0xda, 0xc6, 0x73, 0xa6, 0xc7, + 0x53, 0x93, 0x54, 0x61, 0xa1, 0x11, 0xb0, 0x47, 0xc8, 0x3b, 0x61, 0x80, 0xb5, 0x20, 0x48, 0xda, + 0xb1, 0xd6, 0x9c, 0xe8, 0xb0, 0x81, 0x3e, 0xe2, 0x02, 0xd1, 0x3d, 0xb8, 0x2d, 0x25, 0x5b, 0xa7, + 0x22, 0x0c, 0x6a, 0x6d, 0xd9, 0xb4, 0xe7, 0xb5, 0xb0, 0x03, 0x3c, 0xce, 0x2c, 0x5c, 0x51, 0x2d, + 0xda, 0xbb, 0x23, 0xce, 0x2f, 0x16, 0xcc, 0x29, 0x60, 0x83, 0x23, 0x95, 0xe8, 0xe3, 0xd3, 0x36, + 0x0a, 0x49, 0x3e, 0x29, 0x74, 0xed, 0x74, 0x75, 0xfb, 0xbf, 0x5d, 0x77, 0x3f, 0xbb, 0x75, 0x69, + 0xff, 0x5f, 0x83, 0x52, 0x9b, 0x09, 0xe4, 0x32, 0xbd, 0x45, 0xa9, 0xa5, 0x7a, 0x23, 0xe0, 0x58, + 0x17, 0x7b, 0x71, 0xd4, 0xd5, 0xcd, 0x3f, 0xe9, 0xe7, 0x80, 0xf3, 0xd4, 0x10, 0xdd, 0x67, 0xf5, + 0x8b, 0x22, 0x5a, 0xfd, 0x67, 0xd6, 0xd4, 0x34, 0x60, 0x2a, 0x3e, 0xf9, 0xc6, 0x82, 0x4b, 0xbb, + 0xa1, 0x90, 0xe4, 0xa5, 0xe2, 0x40, 0xc9, 0xc6, 0x47, 0x65, 0xf7, 0xbc, 0x58, 0xa8, 0x22, 0xce, + 0xcd, 0x2f, 0xff, 0xfc, 0xfb, 0xbb, 0xb1, 0x6b, 0x64, 0x41, 0x3f, 0x7b, 0x9d, 0xb5, 0xfc, 0x8d, + 0x09, 0x51, 0x7c, 0x35, 0x66, 0x91, 0xaf, 0x2d, 0x18, 0x7f, 0x80, 0x43, 0xd9, 0x9c, 0x9b, 0x26, + 0xce, 0x2d, 0xcd, 0xe4, 0x06, 0xb9, 0x3e, 0x88, 0x89, 0xf7, 0x4c, 0x59, 0xcf, 0xc9, 0xf7, 0x16, + 0x94, 0x15, 0x6f, 0xbf, 0xe0, 0xbb, 0x18, 0xa1, 0x16, 0x47, 0x09, 0x45, 0x3e, 0x85, 0x49, 0x43, + 0xeb, 0x70, 0x28, 0x9d, 0x72, 0x3f, 0x7c, 0x28, 0x9c, 0x15, 0x9d, 0xd2, 0x21, 0xcb, 0x23, 0x76, + 0xec, 0x71, 0x95, 0xb2, 0x65, 0xd2, 0xab, 0xe7, 0x87, 0xbc, 0x72, 0x3c, 0x7d, 0xf6, 0xfa, 0x57, + 0x16, 0x07, 0xb9, 0xb2, 0xbb, 0x78, 0xa6, 0x72, 0x54, 0x95, 0xf8, 0xd6, 0x82, 0x99, 0x07, 0x28, + 0xf3, 0x77, 0x9a, 0xdc, 0x1c, 0x90, 0xb9, 0xf8, 0x86, 0x57, 0x9c, 0xe1, 0x01, 0x19, 0x81, 0x77, + 0x34, 0x81, 0x37, 0x9d, 0x7b, 0x83, 0x09, 0x98, 0x47, 0x5a, 0xe7, 0xd9, 0xf7, 0x77, 0x35, 0x95, + 0xba, 0xc9, 0x70, 0xdf, 0x5a, 0x25, 0x1d, 0x4d, 0x69, 0x1b, 0xa3, 0xd6, 0x46, 0x93, 0x72, 0x39, + 0x54, 0xe6, 0xa5, 0x22, 0x9c, 0x87, 0x67, 0x24, 0x5c, 0x4d, 0x62, 0x85, 0xdc, 0x19, 0xa5, 0x42, + 0x13, 0xa3, 0x56, 0x60, 0xca, 0xfc, 0x60, 0x41, 0xc9, 0x4c, 0x2f, 0x72, 0xe3, 0x78, 0xc5, 0xbe, + 0xa9, 0x76, 0x8e, 0x57, 0xe1, 0x55, 0xcd, 0x71, 0xd1, 0x19, 0xd8, 0x6b, 0xf7, 0xf5, 0xf0, 0x50, + 0x57, 0xf3, 0x47, 0x0b, 0xca, 0x3d, 0x0a, 0xbd, 0x6f, 0x2f, 0x8e, 0xa4, 0x73, 0x3a, 0x49, 0xf2, + 0xb3, 0x05, 0x25, 0x33, 0x51, 0x4f, 0xf2, 0xea, 0x9b, 0xb4, 0xe7, 0xc8, 0x6b, 0xcd, 0x1c, 0x70, + 0x65, 0x44, 0x9b, 0x6b, 0x2a, 0xcf, 0x73, 0x21, 0x7f, 0xb5, 0xa0, 0xdc, 0xa3, 0x33, 0x5c, 0xc8, + 0xff, 0x8b, 0xb0, 0xfb, 0x62, 0x84, 0x09, 0x85, 0xd2, 0x26, 0x46, 0x28, 0x71, 0xd8, 0x15, 0xb0, + 0x8f, 0xc3, 0x59, 0xf3, 0xdf, 0x31, 0x33, 0x76, 0x75, 0xd4, 0x8c, 0x55, 0x82, 0x34, 0xa1, 0x6c, + 0x4a, 0x14, 0xf4, 0x78, 0xe1, 0x62, 0xb7, 0xce, 0x50, 0x8c, 0x3c, 0x83, 0xd9, 0x8f, 0x68, 0x14, + 0x2a, 0x65, 0xcd, 0xef, 0x5a, 0x72, 0xfd, 0xc4, 0x24, 0xc9, 0x7f, 0xef, 0x8e, 0xa8, 0x56, 0xd5, + 0xd5, 0xee, 0x3a, 0xb7, 0x47, 0xdd, 0xeb, 0x4e, 0x5a, 0xca, 0x28, 0xb9, 0xbe, 0xf5, 0xfb, 0xd1, + 0x92, 0xf5, 0xc7, 0xd1, 0x92, 0xf5, 0xd7, 0xd1, 0x92, 0xf5, 0xf1, 0x5b, 0x67, 0xfb, 0x87, 0x17, + 0xe8, 0x1f, 0xa6, 0x85, 0xff, 0x62, 0x07, 0x25, 0xfd, 0x67, 0xec, 0x8d, 0x7f, 0x03, 0x00, 0x00, + 0xff, 0xff, 0x52, 0xa9, 0xe9, 0x17, 0x71, 0x0e, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1604,6 +1614,18 @@ func (m *RepoAccessQuery) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.ForceHttpBasicAuth { + i-- + if m.ForceHttpBasicAuth { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x98 + } if len(m.GcpServiceAccountKey) > 0 { i -= len(m.GcpServiceAccountKey) copy(dAtA[i:], m.GcpServiceAccountKey) @@ -2049,6 +2071,9 @@ func (m *RepoAccessQuery) Size() (n int) { if l > 0 { n += 2 + l + sovRepository(uint64(l)) } + if m.ForceHttpBasicAuth { + n += 3 + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -3267,6 +3292,26 @@ func (m *RepoAccessQuery) Unmarshal(dAtA []byte) error { } m.GcpServiceAccountKey = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 19: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ForceHttpBasicAuth", 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.ForceHttpBasicAuth = bool(v != 0) default: iNdEx = preIndex skippy, err := skipRepository(dAtA[iNdEx:]) diff --git a/pkg/apiclient/settings/settings.pb.go b/pkg/apiclient/settings/settings.pb.go index 9fbbea430d549..b74110f9005d7 100644 --- a/pkg/apiclient/settings/settings.pb.go +++ b/pkg/apiclient/settings/settings.pb.go @@ -84,9 +84,10 @@ type Settings struct { GoogleAnalytics *GoogleAnalyticsConfig `protobuf:"bytes,7,opt,name=googleAnalytics,proto3" json:"googleAnalytics,omitempty"` KustomizeOptions *v1alpha1.KustomizeOptions `protobuf:"bytes,8,opt,name=kustomizeOptions,proto3" json:"kustomizeOptions,omitempty"` // Help settings - Help *Help `protobuf:"bytes,9,opt,name=help,proto3" json:"help,omitempty"` - Plugins []*Plugin `protobuf:"bytes,10,rep,name=plugins,proto3" json:"plugins,omitempty"` - UserLoginsDisabled bool `protobuf:"varint,11,opt,name=userLoginsDisabled,proto3" json:"userLoginsDisabled,omitempty"` + Help *Help `protobuf:"bytes,9,opt,name=help,proto3" json:"help,omitempty"` + Plugins []*Plugin `protobuf:"bytes,10,rep,name=plugins,proto3" json:"plugins,omitempty"` + UserLoginsDisabled bool `protobuf:"varint,11,opt,name=userLoginsDisabled,proto3" json:"userLoginsDisabled,omitempty"` + // Deprecated: use sidecar plugins instead. ConfigManagementPlugins []*v1alpha1.ConfigManagementPlugin `protobuf:"bytes,12,rep,name=configManagementPlugins,proto3" json:"configManagementPlugins,omitempty"` KustomizeVersions []string `protobuf:"bytes,13,rep,name=kustomizeVersions,proto3" json:"kustomizeVersions,omitempty"` UiCssURL string `protobuf:"bytes,14,opt,name=uiCssURL,proto3" json:"uiCssURL,omitempty"` @@ -361,6 +362,53 @@ func (m *GoogleAnalyticsConfig) GetAnonymizeUsers() bool { return false } +type SettingsPluginsResponse struct { + Plugins []*Plugin `protobuf:"bytes,1,rep,name=plugins,proto3" json:"plugins,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SettingsPluginsResponse) Reset() { *m = SettingsPluginsResponse{} } +func (m *SettingsPluginsResponse) String() string { return proto.CompactTextString(m) } +func (*SettingsPluginsResponse) ProtoMessage() {} +func (*SettingsPluginsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_a480d494da040caa, []int{3} +} +func (m *SettingsPluginsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SettingsPluginsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SettingsPluginsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SettingsPluginsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_SettingsPluginsResponse.Merge(m, src) +} +func (m *SettingsPluginsResponse) XXX_Size() int { + return m.Size() +} +func (m *SettingsPluginsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_SettingsPluginsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_SettingsPluginsResponse proto.InternalMessageInfo + +func (m *SettingsPluginsResponse) GetPlugins() []*Plugin { + if m != nil { + return m.Plugins + } + return nil +} + // Help settings type Help struct { // the URL for getting chat help, this will typically be your Slack channel for support @@ -378,7 +426,7 @@ func (m *Help) Reset() { *m = Help{} } func (m *Help) String() string { return proto.CompactTextString(m) } func (*Help) ProtoMessage() {} func (*Help) Descriptor() ([]byte, []int) { - return fileDescriptor_a480d494da040caa, []int{3} + return fileDescriptor_a480d494da040caa, []int{4} } func (m *Help) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -441,7 +489,7 @@ func (m *Plugin) Reset() { *m = Plugin{} } func (m *Plugin) String() string { return proto.CompactTextString(m) } func (*Plugin) ProtoMessage() {} func (*Plugin) Descriptor() ([]byte, []int) { - return fileDescriptor_a480d494da040caa, []int{4} + return fileDescriptor_a480d494da040caa, []int{5} } func (m *Plugin) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -488,7 +536,7 @@ func (m *DexConfig) Reset() { *m = DexConfig{} } func (m *DexConfig) String() string { return proto.CompactTextString(m) } func (*DexConfig) ProtoMessage() {} func (*DexConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_a480d494da040caa, []int{5} + return fileDescriptor_a480d494da040caa, []int{6} } func (m *DexConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -536,7 +584,7 @@ func (m *Connector) Reset() { *m = Connector{} } func (m *Connector) String() string { return proto.CompactTextString(m) } func (*Connector) ProtoMessage() {} func (*Connector) Descriptor() ([]byte, []int) { - return fileDescriptor_a480d494da040caa, []int{6} + return fileDescriptor_a480d494da040caa, []int{7} } func (m *Connector) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -580,22 +628,23 @@ 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{} } func (m *OIDCConfig) String() string { return proto.CompactTextString(m) } func (*OIDCConfig) ProtoMessage() {} func (*OIDCConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_a480d494da040caa, []int{7} + return fileDescriptor_a480d494da040caa, []int{8} } func (m *OIDCConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -666,11 +715,19 @@ 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") proto.RegisterMapType((map[string]*v1alpha1.ResourceOverride)(nil), "cluster.Settings.ResourceOverridesEntry") proto.RegisterType((*GoogleAnalyticsConfig)(nil), "cluster.GoogleAnalyticsConfig") + proto.RegisterType((*SettingsPluginsResponse)(nil), "cluster.SettingsPluginsResponse") proto.RegisterType((*Help)(nil), "cluster.Help") proto.RegisterMapType((map[string]string)(nil), "cluster.Help.BinaryUrlsEntry") proto.RegisterType((*Plugin)(nil), "cluster.Plugin") @@ -683,79 +740,83 @@ func init() { func init() { proto.RegisterFile("server/settings/settings.proto", fileDescriptor_a480d494da040caa) } var fileDescriptor_a480d494da040caa = []byte{ - // 1148 bytes of a gzipped FileDescriptorProto + // 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, 0x92, 0xe0, 0x43, - 0x65, 0x10, 0xac, 0x1b, 0x57, 0x08, 0x84, 0xa8, 0xa0, 0xb6, 0xab, 0xd6, 0xd4, 0x6d, 0xc3, 0xb6, - 0xe9, 0x01, 0x09, 0x55, 0x93, 0xdd, 0xc7, 0x66, 0xf1, 0x7a, 0x66, 0x35, 0x33, 0x6b, 0xea, 0x1e, - 0xb9, 0x71, 0xe1, 0x02, 0x9f, 0x85, 0x03, 0x9f, 0x80, 0x23, 0x12, 0xf7, 0x08, 0x59, 0x7c, 0x10, - 0x34, 0xb3, 0x7f, 0xb2, 0xb1, 0x5d, 0x40, 0xea, 0x6d, 0xe6, 0xf7, 0x7b, 0xff, 0xe6, 0xcd, 0x7b, - 0x33, 0x0f, 0x76, 0x25, 0x8a, 0x29, 0x8a, 0x8e, 0x44, 0xa5, 0x42, 0x16, 0xc8, 0x62, 0xe1, 0xc4, - 0x82, 0x2b, 0x4e, 0x36, 0xbc, 0x28, 0x91, 0x0a, 0x45, 0xf3, 0x6a, 0xc0, 0x03, 0x6e, 0xb0, 0x8e, - 0x5e, 0xa5, 0x74, 0xf3, 0x66, 0xc0, 0x79, 0x10, 0x61, 0x87, 0xc6, 0x61, 0x87, 0x32, 0xc6, 0x15, - 0x55, 0x21, 0x67, 0x99, 0x72, 0x73, 0x14, 0x84, 0xea, 0x24, 0x39, 0x76, 0x3c, 0x3e, 0xe9, 0x50, - 0x61, 0xd4, 0xbf, 0x33, 0x8b, 0x0f, 0x3d, 0xbf, 0x33, 0xed, 0x76, 0xe2, 0x71, 0xa0, 0x35, 0x65, - 0x87, 0xc6, 0x71, 0x14, 0x7a, 0x46, 0xb7, 0x33, 0x3d, 0xa0, 0x51, 0x7c, 0x42, 0x0f, 0x3a, 0x01, - 0x32, 0x14, 0x54, 0xa1, 0x9f, 0x59, 0xfb, 0xe2, 0x3f, 0xac, 0x2d, 0x9e, 0x84, 0x87, 0xbe, 0xd7, - 0xf1, 0x22, 0x1a, 0x4e, 0xb2, 0x78, 0x5a, 0x0d, 0xd8, 0x7c, 0x96, 0xb1, 0x5f, 0x25, 0x28, 0x66, - 0xad, 0x5f, 0xeb, 0x50, 0xcd, 0x11, 0x72, 0x03, 0x2a, 0x89, 0x88, 0x6c, 0x6b, 0xdf, 0x6a, 0xd7, - 0x7a, 0x1b, 0xf3, 0xd3, 0xbd, 0xca, 0x91, 0x3b, 0x72, 0x35, 0x46, 0x6e, 0x43, 0xcd, 0xc7, 0x57, - 0x7d, 0xce, 0xbe, 0x0d, 0x03, 0xfb, 0xc2, 0xbe, 0xd5, 0xae, 0x77, 0x89, 0x93, 0x65, 0xc6, 0x19, - 0xe4, 0x8c, 0x7b, 0x26, 0x44, 0xfa, 0x00, 0xda, 0x7f, 0xa6, 0x52, 0x31, 0x2a, 0x57, 0x0a, 0x95, - 0xa7, 0xc3, 0x41, 0x3f, 0xa5, 0x7a, 0x97, 0xe7, 0xa7, 0x7b, 0x70, 0xb6, 0x77, 0x4b, 0x6a, 0x64, - 0x1f, 0xea, 0x34, 0x8e, 0x47, 0xf4, 0x18, 0xa3, 0x47, 0x38, 0xb3, 0xd7, 0x74, 0x64, 0x6e, 0x19, - 0x22, 0x2f, 0x60, 0x5b, 0xa0, 0xe4, 0x89, 0xf0, 0xf0, 0xe9, 0x14, 0x85, 0x08, 0x7d, 0x94, 0xf6, - 0xc5, 0xfd, 0x4a, 0xbb, 0xde, 0x6d, 0x17, 0xde, 0xf2, 0x13, 0x3a, 0xee, 0xa2, 0xe8, 0x7d, 0xa6, - 0xc4, 0xcc, 0x5d, 0x36, 0x41, 0x1c, 0x20, 0x52, 0x51, 0x95, 0xc8, 0x1e, 0xf5, 0x03, 0xbc, 0xcf, - 0xe8, 0x71, 0x84, 0xbe, 0xbd, 0xbe, 0x6f, 0xb5, 0xab, 0xee, 0x0a, 0x86, 0x3c, 0x84, 0x46, 0x5a, - 0x09, 0xf7, 0x18, 0x8d, 0x66, 0x2a, 0xf4, 0xa4, 0xbd, 0x61, 0xce, 0xbc, 0x5b, 0x44, 0xf1, 0xe0, - 0x3c, 0x9f, 0x1d, 0x77, 0x51, 0x8d, 0xbc, 0x86, 0xad, 0x71, 0x22, 0x15, 0x9f, 0x84, 0xaf, 0xf1, - 0x69, 0x6c, 0xaa, 0xc9, 0xae, 0x1a, 0x53, 0x4f, 0x9c, 0xb3, 0x02, 0x70, 0xf2, 0x02, 0x30, 0x8b, - 0x97, 0x9e, 0xef, 0x4c, 0xbb, 0x4e, 0x3c, 0x0e, 0x1c, 0x5d, 0x4e, 0x4e, 0xa9, 0x9c, 0x9c, 0xbc, - 0x9c, 0x9c, 0x47, 0x0b, 0x56, 0xdd, 0x25, 0x3f, 0xe4, 0x5d, 0x58, 0x3b, 0xc1, 0x28, 0xb6, 0x6b, - 0xc6, 0xdf, 0x66, 0x11, 0xfa, 0x43, 0x8c, 0x62, 0xd7, 0x50, 0xe4, 0x3d, 0xd8, 0x88, 0xa3, 0x24, - 0x08, 0x99, 0xb4, 0xc1, 0xa4, 0xb9, 0x51, 0x48, 0x1d, 0x1a, 0xdc, 0xcd, 0x79, 0x9d, 0xc3, 0x44, - 0xa2, 0x18, 0x71, 0xbd, 0x1b, 0x84, 0x32, 0xcd, 0x61, 0x3d, 0xcd, 0xe1, 0x32, 0x43, 0x7e, 0xb2, - 0xe0, 0xba, 0x67, 0xb2, 0xf2, 0x98, 0x32, 0x1a, 0xe0, 0x04, 0x99, 0x3a, 0xcc, 0x7c, 0x5d, 0x32, - 0xbe, 0x9e, 0xbf, 0x5d, 0x06, 0xfa, 0x2b, 0x8d, 0xbb, 0x6f, 0x72, 0x4a, 0x3e, 0x80, 0xed, 0x22, - 0x45, 0x2f, 0x50, 0x48, 0x73, 0x17, 0x9b, 0xfb, 0x95, 0x76, 0xcd, 0x5d, 0x26, 0x48, 0x13, 0xaa, - 0x49, 0xd8, 0x97, 0xf2, 0xc8, 0x1d, 0xd9, 0x97, 0x4d, 0xa5, 0x16, 0x7b, 0xd2, 0x86, 0x46, 0x12, - 0xf6, 0x28, 0x63, 0x28, 0xfa, 0x9c, 0x29, 0x64, 0xca, 0x6e, 0x18, 0x91, 0x45, 0x58, 0x97, 0x7c, - 0x0e, 0x69, 0x43, 0x5b, 0x69, 0xc9, 0x97, 0x20, 0x6d, 0x2b, 0xa6, 0x52, 0x7e, 0xcf, 0x85, 0x7f, - 0x48, 0x95, 0x42, 0xc1, 0xec, 0xed, 0xd4, 0xd6, 0x02, 0x4c, 0x6e, 0xc1, 0x65, 0x25, 0xa8, 0x37, - 0x0e, 0x59, 0xf0, 0x18, 0xd5, 0x09, 0xf7, 0x6d, 0x62, 0x04, 0x17, 0x50, 0x7d, 0xce, 0xdc, 0xc1, - 0x21, 0x8a, 0x09, 0x65, 0x3a, 0xbe, 0x2b, 0xe6, 0x9e, 0x96, 0x09, 0xf2, 0x3e, 0x6c, 0x15, 0x20, - 0x97, 0xa1, 0x4e, 0xb1, 0x7d, 0xd5, 0xd8, 0x5d, 0xc2, 0x17, 0xda, 0xc8, 0xe5, 0x5c, 0x1d, 0x89, - 0xc8, 0xbe, 0x66, 0xa4, 0x57, 0x30, 0xfa, 0xf4, 0xf8, 0x0a, 0xbd, 0xbc, 0xdf, 0x76, 0x4c, 0x0c, - 0x65, 0x88, 0xdc, 0x86, 0x2b, 0x1e, 0x67, 0x4a, 0xf0, 0x28, 0x42, 0xf1, 0x84, 0x4e, 0x50, 0xc6, - 0xd4, 0x43, 0xfb, 0xba, 0x31, 0xb9, 0x8a, 0x22, 0x9f, 0xc1, 0x0d, 0x1a, 0xc7, 0x72, 0xc8, 0xee, - 0xb1, 0x59, 0x81, 0xe6, 0x1e, 0x6c, 0xe3, 0xe1, 0xcd, 0x02, 0xcd, 0x5f, 0x2c, 0xd8, 0x59, 0xfd, - 0x6c, 0x90, 0x2d, 0xa8, 0x8c, 0x71, 0x96, 0xbe, 0x97, 0xae, 0x5e, 0x12, 0x1f, 0x2e, 0x4e, 0x69, - 0x94, 0x60, 0xf6, 0x44, 0xbe, 0x65, 0xc3, 0x2e, 0xba, 0x75, 0x53, 0xe3, 0x9f, 0x5e, 0xf8, 0xc4, - 0x6a, 0xbd, 0x84, 0x6b, 0x2b, 0xdf, 0x13, 0xb2, 0x0b, 0x90, 0xdf, 0xee, 0x70, 0x90, 0xc5, 0x56, - 0x42, 0x74, 0x4d, 0x50, 0xc6, 0xd9, 0x4c, 0x97, 0xee, 0x91, 0x44, 0x21, 0x4d, 0xac, 0x55, 0x77, - 0x01, 0x6d, 0xfd, 0x66, 0xc1, 0x9a, 0x6e, 0x7b, 0x62, 0xc3, 0x86, 0x77, 0x42, 0xcd, 0xbd, 0xa5, - 0xd6, 0xf2, 0xad, 0x2e, 0x78, 0xbd, 0x7c, 0x8e, 0xaf, 0x94, 0x31, 0x52, 0x73, 0x8b, 0x3d, 0xb9, - 0x0b, 0x70, 0x1c, 0x32, 0x2a, 0x66, 0x47, 0x22, 0x92, 0x76, 0xc5, 0x74, 0xef, 0x3b, 0xe7, 0xde, - 0x13, 0xa7, 0x57, 0xf0, 0xe9, 0x2b, 0x5c, 0x52, 0x68, 0xde, 0x85, 0xc6, 0x02, 0xbd, 0x22, 0xdb, - 0x57, 0xcb, 0xd9, 0xae, 0x95, 0xb3, 0x73, 0x13, 0xd6, 0xd3, 0x1e, 0x26, 0x04, 0xd6, 0x18, 0x9d, - 0x60, 0xa6, 0x66, 0xd6, 0xad, 0xcf, 0xa1, 0x56, 0x7c, 0x59, 0xa4, 0x0b, 0xe0, 0x71, 0xc6, 0xd0, - 0x53, 0x5c, 0x48, 0xdb, 0x32, 0x81, 0x9e, 0x7d, 0x6d, 0xfd, 0x9c, 0x72, 0x4b, 0x52, 0xad, 0x3b, - 0x50, 0x2b, 0x88, 0x55, 0x1e, 0x34, 0xa6, 0x66, 0x71, 0x1e, 0x98, 0x59, 0xb7, 0x7e, 0xac, 0x40, - 0xe9, 0x9b, 0x5b, 0xa9, 0xb6, 0x03, 0xeb, 0xa1, 0x94, 0x09, 0x8a, 0x4c, 0x31, 0xdb, 0x91, 0x36, - 0x54, 0xbd, 0x28, 0x44, 0xa6, 0x86, 0x03, 0xf3, 0x93, 0xd6, 0x7a, 0x97, 0xe6, 0xa7, 0x7b, 0xd5, - 0x7e, 0x86, 0xb9, 0x05, 0x4b, 0x0e, 0xa0, 0xee, 0x45, 0x61, 0x4e, 0xa4, 0x1f, 0x66, 0xaf, 0x31, - 0x3f, 0xdd, 0xab, 0xf7, 0x47, 0xc3, 0x42, 0xbe, 0x2c, 0xa3, 0x9d, 0x4a, 0x8f, 0xc7, 0xd9, 0xb7, - 0x59, 0x73, 0xb3, 0x1d, 0x79, 0x09, 0x9b, 0xa1, 0xff, 0x9c, 0x8f, 0x91, 0xf5, 0xcd, 0x08, 0x61, - 0xaf, 0x9b, 0xdc, 0xdc, 0x5a, 0xf1, 0x87, 0x3b, 0xc3, 0xb2, 0xa0, 0xb9, 0xae, 0xde, 0xf6, 0xfc, - 0x74, 0x6f, 0x73, 0x38, 0x28, 0xe1, 0xee, 0x79, 0x7b, 0xcd, 0x19, 0x90, 0x65, 0xbd, 0x15, 0xd7, - 0xfc, 0xf8, 0x7c, 0x53, 0x7d, 0xfc, 0xaf, 0x4d, 0x95, 0xce, 0x40, 0x4e, 0x31, 0xc4, 0xe9, 0x61, - 0xc2, 0x31, 0xf6, 0x4b, 0xf5, 0xd1, 0xfd, 0x06, 0x1a, 0xf9, 0x4c, 0xf0, 0x0c, 0xc5, 0x34, 0xf4, - 0x90, 0x7c, 0x09, 0x95, 0x07, 0xa8, 0xc8, 0xce, 0xd2, 0xd0, 0x60, 0x06, 0xa5, 0xe6, 0xf6, 0x12, - 0xde, 0xb2, 0x7f, 0xf8, 0xf3, 0xef, 0x9f, 0x2f, 0x10, 0xb2, 0x65, 0x86, 0xbf, 0xe9, 0x41, 0x31, - 0x78, 0xf5, 0xfa, 0xbf, 0xcf, 0x77, 0xad, 0x3f, 0xe6, 0xbb, 0xd6, 0x5f, 0xf3, 0x5d, 0xeb, 0xeb, - 0x8f, 0xfe, 0xdf, 0x10, 0x98, 0xde, 0x61, 0x61, 0xe4, 0x78, 0xdd, 0x8c, 0x6c, 0x77, 0xfe, 0x09, - 0x00, 0x00, 0xff, 0xff, 0xf0, 0x33, 0x47, 0xc2, 0xa1, 0x0a, 0x00, 0x00, + 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. @@ -772,6 +833,8 @@ const _ = grpc.SupportPackageIsVersion4 type SettingsServiceClient interface { // Get returns Argo CD settings Get(ctx context.Context, in *SettingsQuery, opts ...grpc.CallOption) (*Settings, error) + // Get returns Argo CD plugins + GetPlugins(ctx context.Context, in *SettingsQuery, opts ...grpc.CallOption) (*SettingsPluginsResponse, error) } type settingsServiceClient struct { @@ -791,10 +854,21 @@ func (c *settingsServiceClient) Get(ctx context.Context, in *SettingsQuery, opts return out, nil } +func (c *settingsServiceClient) GetPlugins(ctx context.Context, in *SettingsQuery, opts ...grpc.CallOption) (*SettingsPluginsResponse, error) { + out := new(SettingsPluginsResponse) + err := c.cc.Invoke(ctx, "/cluster.SettingsService/GetPlugins", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // SettingsServiceServer is the server API for SettingsService service. type SettingsServiceServer interface { // Get returns Argo CD settings Get(context.Context, *SettingsQuery) (*Settings, error) + // Get returns Argo CD plugins + GetPlugins(context.Context, *SettingsQuery) (*SettingsPluginsResponse, error) } // UnimplementedSettingsServiceServer can be embedded to have forward compatible implementations. @@ -804,6 +878,9 @@ type UnimplementedSettingsServiceServer struct { func (*UnimplementedSettingsServiceServer) Get(ctx context.Context, req *SettingsQuery) (*Settings, error) { return nil, status.Errorf(codes.Unimplemented, "method Get not implemented") } +func (*UnimplementedSettingsServiceServer) GetPlugins(ctx context.Context, req *SettingsQuery) (*SettingsPluginsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPlugins not implemented") +} func RegisterSettingsServiceServer(s *grpc.Server, srv SettingsServiceServer) { s.RegisterService(&_SettingsService_serviceDesc, srv) @@ -827,6 +904,24 @@ func _SettingsService_Get_Handler(srv interface{}, ctx context.Context, dec func return interceptor(ctx, in, info, handler) } +func _SettingsService_GetPlugins_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SettingsQuery) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(SettingsServiceServer).GetPlugins(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cluster.SettingsService/GetPlugins", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(SettingsServiceServer).GetPlugins(ctx, req.(*SettingsQuery)) + } + return interceptor(ctx, in, info, handler) +} + var _SettingsService_serviceDesc = grpc.ServiceDesc{ ServiceName: "cluster.SettingsService", HandlerType: (*SettingsServiceServer)(nil), @@ -835,6 +930,10 @@ var _SettingsService_serviceDesc = grpc.ServiceDesc{ MethodName: "Get", Handler: _SettingsService_Get_Handler, }, + { + MethodName: "GetPlugins", + Handler: _SettingsService_GetPlugins_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "server/settings/settings.proto", @@ -1199,6 +1298,47 @@ func (m *GoogleAnalyticsConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *SettingsPluginsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SettingsPluginsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SettingsPluginsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Plugins) > 0 { + for iNdEx := len(m.Plugins) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Plugins[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSettings(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *Help) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1399,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] @@ -1625,6 +1775,24 @@ func (m *GoogleAnalyticsConfig) Size() (n int) { return n } +func (m *SettingsPluginsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Plugins) > 0 { + for _, e := range m.Plugins { + l = e.Size() + n += 1 + l + sovSettings(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *Help) Size() (n int) { if m == nil { return 0 @@ -1748,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) } @@ -2794,6 +2965,91 @@ func (m *GoogleAnalyticsConfig) Unmarshal(dAtA []byte) error { } return nil } +func (m *SettingsPluginsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSettings + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SettingsPluginsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SettingsPluginsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Plugins", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSettings + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSettings + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSettings + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Plugins = append(m.Plugins, &Plugin{}) + if err := m.Plugins[len(m.Plugins)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSettings(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSettings + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *Help) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -3637,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/apiclient/settings/settings.pb.gw.go b/pkg/apiclient/settings/settings.pb.gw.go index 67f7bd5db1547..238ec7604fe88 100644 --- a/pkg/apiclient/settings/settings.pb.gw.go +++ b/pkg/apiclient/settings/settings.pb.gw.go @@ -51,6 +51,24 @@ func local_request_SettingsService_Get_0(ctx context.Context, marshaler runtime. } +func request_SettingsService_GetPlugins_0(ctx context.Context, marshaler runtime.Marshaler, client SettingsServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SettingsQuery + var metadata runtime.ServerMetadata + + msg, err := client.GetPlugins(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_SettingsService_GetPlugins_0(ctx context.Context, marshaler runtime.Marshaler, server SettingsServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SettingsQuery + var metadata runtime.ServerMetadata + + msg, err := server.GetPlugins(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterSettingsServiceHandlerServer registers the http handlers for service SettingsService to "mux". // UnaryRPC :call SettingsServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -80,6 +98,29 @@ func RegisterSettingsServiceHandlerServer(ctx context.Context, mux *runtime.Serv }) + mux.Handle("GET", pattern_SettingsService_GetPlugins_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_SettingsService_GetPlugins_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_SettingsService_GetPlugins_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -141,13 +182,37 @@ func RegisterSettingsServiceHandlerClient(ctx context.Context, mux *runtime.Serv }) + mux.Handle("GET", pattern_SettingsService_GetPlugins_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_SettingsService_GetPlugins_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_SettingsService_GetPlugins_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } var ( pattern_SettingsService_Get_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "settings"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_SettingsService_GetPlugins_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "settings", "plugins"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( forward_SettingsService_Get_0 = runtime.ForwardResponseMessage + + forward_SettingsService_GetPlugins_0 = runtime.ForwardResponseMessage ) diff --git a/pkg/apiclient/version/version.pb.go b/pkg/apiclient/version/version.pb.go index 35474d63124ed..0b58bf4a6cede 100644 --- a/pkg/apiclient/version/version.pb.go +++ b/pkg/apiclient/version/version.pb.go @@ -46,6 +46,7 @@ type VersionMessage struct { HelmVersion string `protobuf:"bytes,11,opt,name=HelmVersion,proto3" json:"HelmVersion,omitempty"` KubectlVersion string `protobuf:"bytes,12,opt,name=KubectlVersion,proto3" json:"KubectlVersion,omitempty"` JsonnetVersion string `protobuf:"bytes,13,opt,name=JsonnetVersion,proto3" json:"JsonnetVersion,omitempty"` + ExtraBuildInfo string `protobuf:"bytes,14,opt,name=ExtraBuildInfo,proto3" json:"ExtraBuildInfo,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -168,6 +169,13 @@ func (m *VersionMessage) GetJsonnetVersion() string { return "" } +func (m *VersionMessage) GetExtraBuildInfo() string { + if m != nil { + return m.ExtraBuildInfo + } + return "" +} + func init() { proto.RegisterType((*VersionMessage)(nil), "version.VersionMessage") } @@ -175,32 +183,33 @@ func init() { func init() { proto.RegisterFile("server/version/version.proto", fileDescriptor_8be80977d07a4107) } var fileDescriptor_8be80977d07a4107 = []byte{ - // 399 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x92, 0xdf, 0x6a, 0xdb, 0x30, - 0x18, 0xc5, 0x71, 0xb2, 0xe5, 0x8f, 0x92, 0x85, 0x21, 0x46, 0x66, 0xbc, 0x10, 0x42, 0x2e, 0xc6, - 0x18, 0xcc, 0x86, 0x6c, 0x4f, 0x90, 0x6c, 0x64, 0x2c, 0x0c, 0xc2, 0x32, 0x7a, 0xd1, 0x3b, 0xd9, - 0xf9, 0xe2, 0xaa, 0xb5, 0xfc, 0x19, 0x59, 0x36, 0xb4, 0x97, 0x7d, 0x85, 0x42, 0x9f, 0xa9, 0x97, - 0x85, 0xbe, 0x40, 0x09, 0x7d, 0x90, 0x62, 0xd9, 0x72, 0x9b, 0xf6, 0xca, 0x3a, 0xe7, 0xfc, 0x7c, - 0x10, 0x1c, 0x91, 0x51, 0x0a, 0x32, 0x07, 0xe9, 0xe5, 0x20, 0x53, 0x8e, 0xb1, 0xf9, 0xba, 0x89, - 0x44, 0x85, 0xb4, 0x5d, 0x49, 0x67, 0x14, 0x22, 0x86, 0x11, 0x78, 0x2c, 0xe1, 0x1e, 0x8b, 0x63, - 0x54, 0x4c, 0x71, 0x8c, 0xd3, 0x12, 0x73, 0x3e, 0x55, 0xa9, 0x56, 0x7e, 0xb6, 0xf3, 0x40, 0x24, - 0xea, 0xbc, 0x0c, 0xa7, 0xd7, 0x4d, 0x32, 0x38, 0x2a, 0x6b, 0xfe, 0x42, 0x9a, 0xb2, 0x10, 0xa8, - 0x4d, 0xda, 0x95, 0x63, 0x5b, 0x13, 0xeb, 0x4b, 0xf7, 0x9f, 0x91, 0x74, 0x44, 0xba, 0xf3, 0x8c, - 0x47, 0xdb, 0x9f, 0x4c, 0x81, 0xdd, 0xd0, 0xd9, 0x93, 0x51, 0xa4, 0x4b, 0xae, 0x16, 0x28, 0x04, - 0x57, 0x76, 0xb3, 0x4c, 0x6b, 0x83, 0x0e, 0x49, 0x6b, 0xc9, 0xd5, 0x7f, 0x16, 0xda, 0x6f, 0x74, - 0x54, 0x29, 0x3a, 0x25, 0xfd, 0xe2, 0x24, 0x01, 0x36, 0xaa, 0xa8, 0x7d, 0xab, 0xd3, 0x03, 0x4f, - 0x37, 0xa3, 0xb9, 0x53, 0xab, 0x6a, 0x36, 0x06, 0x75, 0x48, 0x67, 0x81, 0x22, 0xe1, 0x11, 0x48, - 0xbb, 0xad, 0xc3, 0x5a, 0x17, 0xd9, 0x3a, 0x62, 0x6a, 0x87, 0x52, 0xd8, 0x9d, 0x32, 0x33, 0x9a, - 0x7e, 0x25, 0xef, 0x57, 0x59, 0xaa, 0x50, 0xf0, 0x0b, 0x30, 0xe5, 0x44, 0x33, 0xaf, 0x7c, 0x3a, - 0x21, 0xbd, 0xdf, 0x10, 0x09, 0x83, 0xf5, 0x34, 0xf6, 0xdc, 0xa2, 0x9f, 0xc9, 0x60, 0x95, 0xf9, - 0x10, 0xa8, 0xc8, 0x40, 0x7d, 0x0d, 0xbd, 0x70, 0x0b, 0xee, 0x4f, 0x8a, 0x71, 0x0c, 0xca, 0x70, - 0xef, 0x4a, 0xee, 0xd0, 0x9d, 0xf9, 0xf5, 0x2e, 0x1b, 0x90, 0x39, 0x0f, 0x80, 0xae, 0xeb, 0x5d, - 0xe8, 0xd0, 0x2d, 0x37, 0x75, 0xcd, 0xa6, 0xee, 0xaf, 0x62, 0x53, 0xe7, 0xa3, 0x6b, 0x5e, 0xc8, - 0xe1, 0xa6, 0xd3, 0x0f, 0x97, 0x77, 0x0f, 0x57, 0x8d, 0x01, 0xed, 0xeb, 0x37, 0x52, 0x41, 0xf3, - 0xf9, 0xcd, 0x7e, 0x6c, 0xdd, 0xee, 0xc7, 0xd6, 0xfd, 0x7e, 0x6c, 0x1d, 0xff, 0x08, 0xb9, 0x3a, - 0xc9, 0x7c, 0x37, 0x40, 0xe1, 0x31, 0x19, 0x62, 0x22, 0xf1, 0x54, 0x1f, 0xbe, 0x05, 0x5b, 0x2f, - 0x9f, 0x79, 0xc9, 0x59, 0x58, 0xfc, 0x1d, 0x44, 0x1c, 0x62, 0x65, 0x3a, 0xfc, 0x96, 0xbe, 0xc2, - 0xf7, 0xc7, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x97, 0xec, 0x06, 0xab, 0x02, 0x00, 0x00, + // 415 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x92, 0xd1, 0x6a, 0x14, 0x31, + 0x18, 0x85, 0x99, 0x56, 0x77, 0xdb, 0x74, 0x5d, 0x24, 0x48, 0x0d, 0xeb, 0xb2, 0x94, 0xbd, 0x10, + 0x11, 0x9c, 0x81, 0xea, 0x13, 0x6c, 0x2d, 0x55, 0x8b, 0x50, 0xac, 0x78, 0xe1, 0x5d, 0x66, 0xfa, + 0xef, 0x18, 0x9d, 0xe4, 0x1f, 0x32, 0xff, 0x2c, 0xea, 0xa5, 0xaf, 0xe0, 0xfb, 0x78, 0xed, 0xa5, + 0xe0, 0x0b, 0xc8, 0xe2, 0x83, 0x48, 0x92, 0xc9, 0xe8, 0xd8, 0xab, 0xcd, 0x39, 0xe7, 0xdb, 0x43, + 0x98, 0x13, 0x36, 0x6f, 0xc0, 0x6e, 0xc0, 0x66, 0x1b, 0xb0, 0x8d, 0x42, 0x13, 0x7f, 0xd3, 0xda, + 0x22, 0x21, 0x1f, 0x77, 0x72, 0x36, 0x2f, 0x11, 0xcb, 0x0a, 0x32, 0x59, 0xab, 0x4c, 0x1a, 0x83, + 0x24, 0x49, 0xa1, 0x69, 0x02, 0x36, 0xbb, 0xd7, 0xa5, 0x5e, 0xe5, 0xed, 0x3a, 0x03, 0x5d, 0xd3, + 0xa7, 0x10, 0x2e, 0xbf, 0xed, 0xb2, 0xe9, 0x9b, 0x50, 0xf3, 0x12, 0x9a, 0x46, 0x96, 0xc0, 0x05, + 0x1b, 0x77, 0x8e, 0x48, 0x8e, 0x92, 0x07, 0xfb, 0xaf, 0xa2, 0xe4, 0x73, 0xb6, 0xbf, 0x6a, 0x55, + 0x75, 0xf5, 0x54, 0x12, 0x88, 0x1d, 0x9f, 0xfd, 0x35, 0x5c, 0x7a, 0xa6, 0xe8, 0x04, 0xb5, 0x56, + 0x24, 0x76, 0x43, 0xda, 0x1b, 0xfc, 0x90, 0x8d, 0xce, 0x14, 0xbd, 0x96, 0xa5, 0xb8, 0xe1, 0xa3, + 0x4e, 0xf1, 0x25, 0x9b, 0xb8, 0x93, 0x05, 0xb8, 0x24, 0x57, 0x7b, 0xd3, 0xa7, 0x03, 0xcf, 0x37, + 0x63, 0xbc, 0xd3, 0xa8, 0x6b, 0x8e, 0x06, 0x9f, 0xb1, 0xbd, 0x13, 0xd4, 0xb5, 0xaa, 0xc0, 0x8a, + 0xb1, 0x0f, 0x7b, 0xed, 0xb2, 0x8b, 0x4a, 0xd2, 0x1a, 0xad, 0x16, 0x7b, 0x21, 0x8b, 0x9a, 0x3f, + 0x64, 0xb7, 0xcf, 0xdb, 0x86, 0x50, 0xab, 0xcf, 0x10, 0xcb, 0x99, 0x67, 0xae, 0xf9, 0xfc, 0x88, + 0x1d, 0x3c, 0x83, 0x4a, 0x47, 0xec, 0xc0, 0x63, 0xff, 0x5a, 0xfc, 0x3e, 0x9b, 0x9e, 0xb7, 0x39, + 0x14, 0x54, 0x45, 0x68, 0xe2, 0xa1, 0xff, 0x5c, 0xc7, 0xbd, 0x68, 0xd0, 0x18, 0xa0, 0xc8, 0xdd, + 0x0a, 0xdc, 0xd0, 0x75, 0xdc, 0xe9, 0x47, 0xb2, 0xd2, 0x7f, 0xdf, 0xe7, 0x66, 0x8d, 0x62, 0x1a, + 0xb8, 0xa1, 0x7b, 0x9c, 0xf7, 0xfb, 0x5d, 0x82, 0xdd, 0xa8, 0x02, 0xf8, 0x45, 0xbf, 0x1f, 0x3f, + 0x4c, 0xc3, 0xf6, 0x69, 0xdc, 0x3e, 0x3d, 0x75, 0xdb, 0xcf, 0xee, 0xa6, 0xf1, 0x25, 0x0d, 0xb7, + 0x5f, 0xde, 0xf9, 0xf2, 0xf3, 0xf7, 0xd7, 0x9d, 0x29, 0x9f, 0xf8, 0xb7, 0xd4, 0x41, 0xab, 0xd5, + 0xf7, 0xed, 0x22, 0xf9, 0xb1, 0x5d, 0x24, 0xbf, 0xb6, 0x8b, 0xe4, 0xed, 0x93, 0x52, 0xd1, 0xbb, + 0x36, 0x4f, 0x0b, 0xd4, 0x99, 0xb4, 0x25, 0xd6, 0x16, 0xdf, 0xfb, 0xc3, 0xa3, 0xe2, 0x2a, 0xdb, + 0x1c, 0x67, 0xf5, 0x87, 0xd2, 0xfd, 0xbb, 0xa8, 0x14, 0x18, 0x8a, 0x1d, 0xf9, 0xc8, 0x5f, 0xe1, + 0xf1, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd2, 0x21, 0xc0, 0xd1, 0xd3, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -309,6 +318,13 @@ func (m *VersionMessage) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.ExtraBuildInfo) > 0 { + i -= len(m.ExtraBuildInfo) + copy(dAtA[i:], m.ExtraBuildInfo) + i = encodeVarintVersion(dAtA, i, uint64(len(m.ExtraBuildInfo))) + i-- + dAtA[i] = 0x72 + } if len(m.JsonnetVersion) > 0 { i -= len(m.JsonnetVersion) copy(dAtA[i:], m.JsonnetVersion) @@ -461,6 +477,10 @@ func (m *VersionMessage) Size() (n int) { if l > 0 { n += 1 + l + sovVersion(uint64(l)) } + l = len(m.ExtraBuildInfo) + if l > 0 { + n += 1 + l + sovVersion(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -886,6 +906,38 @@ func (m *VersionMessage) Unmarshal(dAtA []byte) error { } m.JsonnetVersion = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ExtraBuildInfo", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowVersion + } + 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 ErrInvalidLengthVersion + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthVersion + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ExtraBuildInfo = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipVersion(dAtA[iNdEx:]) diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index 754988e464117..2b0f2e90d00a9 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -8,9 +8,14 @@ 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,AppProjectSpec,SourceNamespaces API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,AppProjectSpec,SourceRepos API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationMatchExpression,Values +API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationPreservedFields,Annotations +API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationPreservedFields,Labels +API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSetResourceIgnoreDifferences,JQPathExpressions +API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSetResourceIgnoreDifferences,JSONPointers API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSetRolloutStep,MatchExpressions API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSetRolloutStrategy,Steps API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSetSpec,Generators +API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSetSpec,GoTemplateOptions API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSetStatus,ApplicationStatus API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSetStatus,Conditions API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSetTemplateMeta,Finalizers @@ -20,8 +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,ApplicationSourcePluginParameter,Array -API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSpec,IgnoreDifferences +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 @@ -31,6 +35,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,ApplicationTree,Hosts API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationTree,Nodes API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationTree,OrphanedNodes +API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ChartDetails,Maintainers API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,Cluster,Namespaces API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ClusterInfo,APIVersions API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,Command,Args @@ -47,6 +52,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,MergeGenerator,MergeKeys API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,NestedMergeGenerator,MergeKeys API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,Operation,Info +API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,OptionalArray,Array API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,OrphanedResourcesMonitorSettings,Ignore API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,OverrideIgnoreDiff,JQPathExpressions API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,OverrideIgnoreDiff,JSONPointers @@ -55,6 +61,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,ProjectRole,JWTTokens API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ProjectRole,Policies API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,PullRequestGenerator,Filters +API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,PullRequestGeneratorAzureDevOps,Labels API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,PullRequestGeneratorGitLab,Labels API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,PullRequestGeneratorGithub,Labels API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,RepositoryCertificate,CertData @@ -73,6 +80,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,RevisionHistory,Revisions API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,RevisionMetadata,Tags API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,SCMProviderGenerator,Filters +API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,SCMProviderGeneratorAWSCodeCommit,TagFilters API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,SCMProviderGeneratorFilter,PathsDoNotExist API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,SCMProviderGeneratorFilter,PathsExist API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,SyncOperation,Manifests @@ -96,6 +104,7 @@ API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/applicat API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,JWTToken,IssuedAt API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,KustomizeOptions,BinaryPath API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,KustomizeOptions,BuildOptions +API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,PullRequestGenerator,AzureDevOps API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,PullRequestGenerator,GitLab API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,RefTarget,Chart API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,RefTarget,Repo @@ -112,6 +121,7 @@ API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/applicat API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ResourceOverride,Actions API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ResourceOverride,HealthLua API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ResourceOverride,IgnoreDifferences +API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ResourceOverride,IgnoreResourceUpdates API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ResourceOverride,KnownTypeFields API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ResourceOverride,UseOpenLibs API rule violation: names_match,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,objectMeta,Name diff --git a/pkg/apis/application/register.go b/pkg/apis/application/register.go index 944fe60c7f09b..66f712c619450 100644 --- a/pkg/apis/application/register.go +++ b/pkg/apis/application/register.go @@ -19,7 +19,7 @@ const ( AppProjectFullName string = AppProjectPlural + "." + Group // ApplicationSet constants - ApplicationSetKind string = "Applicationset" + ApplicationSetKind string = "ApplicationSet" ApplicationSetSingular string = "applicationset" ApplicationSetShortName string = "appset" ApplicationSetPlural string = "applicationsets" 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 56b1bcfad98be..389f421fed400 100644 --- a/pkg/apis/application/v1alpha1/applicationset_types.go +++ b/pkg/apis/application/v1alpha1/applicationset_types.go @@ -22,6 +22,7 @@ import ( "sort" "github.com/argoproj/argo-cd/v2/common" + "github.com/argoproj/argo-cd/v2/util/security" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -48,17 +49,28 @@ type ApplicationSet struct { } // RBACName formats fully qualified application name for RBAC check. -func (a *ApplicationSet) RBACName() string { - return fmt.Sprintf("%s/%s", a.Spec.Template.Spec.GetProject(), a.ObjectMeta.Name) +func (a *ApplicationSet) RBACName(defaultNS string) string { + return security.RBACName(defaultNS, a.Spec.Template.Spec.GetProject(), a.Namespace, a.Name) } // ApplicationSetSpec represents a class of application set state. type ApplicationSetSpec struct { - GoTemplate bool `json:"goTemplate,omitempty" protobuf:"bytes,1,name=goTemplate"` - Generators []ApplicationSetGenerator `json:"generators" protobuf:"bytes,2,name=generators"` - Template ApplicationSetTemplate `json:"template" protobuf:"bytes,3,name=template"` - SyncPolicy *ApplicationSetSyncPolicy `json:"syncPolicy,omitempty" protobuf:"bytes,4,name=syncPolicy"` - Strategy *ApplicationSetStrategy `json:"strategy,omitempty" protobuf:"bytes,5,opt,name=strategy"` + GoTemplate bool `json:"goTemplate,omitempty" protobuf:"bytes,1,name=goTemplate"` + Generators []ApplicationSetGenerator `json:"generators" protobuf:"bytes,2,name=generators"` + Template ApplicationSetTemplate `json:"template" protobuf:"bytes,3,name=template"` + SyncPolicy *ApplicationSetSyncPolicy `json:"syncPolicy,omitempty" protobuf:"bytes,4,name=syncPolicy"` + Strategy *ApplicationSetStrategy `json:"strategy,omitempty" protobuf:"bytes,5,opt,name=strategy"` + PreservedFields *ApplicationPreservedFields `json:"preservedFields,omitempty" protobuf:"bytes,6,opt,name=preservedFields"` + GoTemplateOptions []string `json:"goTemplateOptions,omitempty" protobuf:"bytes,7,opt,name=goTemplateOptions"` + // 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 { + Annotations []string `json:"annotations,omitempty" protobuf:"bytes,1,name=annotations"` + Labels []string `json:"labels,omitempty" protobuf:"bytes,2,name=labels"` } // ApplicationSetStrategy configures how generated Applications are updated in sequence. @@ -82,11 +94,72 @@ type ApplicationMatchExpression struct { Values []string `json:"values,omitempty" protobuf:"bytes,3,opt,name=values"` } +// ApplicationsSyncPolicy representation +// "create-only" means applications are only created. If the generator's result contains update, applications won't be updated +// "create-update" means applications are only created/Updated. If the generator's result contains update, applications will be updated, but not deleted +// "create-delete" means applications are only created/deleted. If the generator's result contains update, applications won't be updated, if it results in deleted applications, the applications will be deleted +// "sync" means create/update/deleted. If the generator's result contains update, applications will be updated, if it results in deleted applications, the applications will be deleted +// If no ApplicationsSyncPolicy is defined, it defaults it to sync +type ApplicationsSyncPolicy string + +// sync / create-only / create-update / create-delete +const ( + ApplicationsSyncPolicyCreateOnly ApplicationsSyncPolicy = "create-only" + ApplicationsSyncPolicyCreateUpdate ApplicationsSyncPolicy = "create-update" + ApplicationsSyncPolicyCreateDelete ApplicationsSyncPolicy = "create-delete" + ApplicationsSyncPolicySync ApplicationsSyncPolicy = "sync" +) + +func (s ApplicationsSyncPolicy) AllowUpdate() bool { + return s == ApplicationsSyncPolicyCreateUpdate || s == ApplicationsSyncPolicySync +} + +func (s ApplicationsSyncPolicy) AllowDelete() bool { + return s == ApplicationsSyncPolicySync || s == ApplicationsSyncPolicyCreateDelete +} + // ApplicationSetSyncPolicy configures how generated Applications will relate to their // ApplicationSet. type ApplicationSetSyncPolicy struct { // PreserveResourcesOnDeletion will preserve resources on deletion. If PreserveResourcesOnDeletion is set to true, these Applications will not be deleted. PreserveResourcesOnDeletion bool `json:"preserveResourcesOnDeletion,omitempty" protobuf:"bytes,1,name=syncPolicy"` + // ApplicationsSync represents the policy applied on the generated applications. Possible values are create-only, create-update, create-delete, sync + // +kubebuilder:validation:Optional + // +kubebuilder:validation:Enum=create-only;create-update;create-delete;sync + ApplicationsSync *ApplicationsSyncPolicy `json:"applicationsSync,omitempty" protobuf:"bytes,2,opt,name=applicationsSync,casttype=ApplicationsSyncPolicy"` +} + +// ApplicationSetIgnoreDifferences configures how the ApplicationSet controller will ignore differences in live +// applications when applying changes from generated applications. +type ApplicationSetIgnoreDifferences []ApplicationSetResourceIgnoreDifferences + +func (a ApplicationSetIgnoreDifferences) ToApplicationIgnoreDifferences() []ResourceIgnoreDifferences { + var result []ResourceIgnoreDifferences + for _, item := range a { + result = append(result, item.ToApplicationResourceIgnoreDifferences()) + } + return result +} + +// ApplicationSetResourceIgnoreDifferences configures how the ApplicationSet controller will ignore differences in live +// applications when applying changes from generated applications. +type ApplicationSetResourceIgnoreDifferences struct { + // Name is the name of the application to ignore differences for. If not specified, the rule applies to all applications. + Name string `json:"name,omitempty" protobuf:"bytes,1,name=name"` + // JSONPointers is a list of JSON pointers to fields to ignore differences for. + JSONPointers []string `json:"jsonPointers,omitempty" protobuf:"bytes,2,name=jsonPointers"` + // JQPathExpressions is a list of JQ path expressions to fields to ignore differences for. + JQPathExpressions []string `json:"jqPathExpressions,omitempty" protobuf:"bytes,3,name=jqExpressions"` +} + +func (a *ApplicationSetResourceIgnoreDifferences) ToApplicationResourceIgnoreDifferences() ResourceIgnoreDifferences { + return ResourceIgnoreDifferences{ + Kind: ApplicationSchemaGroupVersionKind.Kind, + Group: ApplicationSchemaGroupVersionKind.Group, + Name: a.Name, + JSONPointers: a.JSONPointers, + JQPathExpressions: a.JQPathExpressions, + } } // ApplicationSetTemplate represents argocd ApplicationSpec @@ -118,6 +191,8 @@ type ApplicationSetGenerator struct { // Selector allows to post-filter all generator. Selector *metav1.LabelSelector `json:"selector,omitempty" protobuf:"bytes,9,name=selector"` + + Plugin *PluginGenerator `json:"plugin,omitempty" protobuf:"bytes,10,name=plugin"` } // ApplicationSetNestedGenerator represents a generator nested within a combination-type generator (MatrixGenerator or @@ -138,6 +213,8 @@ type ApplicationSetNestedGenerator struct { // Selector allows to post-filter all generator. Selector *metav1.LabelSelector `json:"selector,omitempty" protobuf:"bytes,9,name=selector"` + + Plugin *PluginGenerator `json:"plugin,omitempty" protobuf:"bytes,10,name=plugin"` } type ApplicationSetNestedGenerators []ApplicationSetNestedGenerator @@ -153,6 +230,10 @@ type ApplicationSetTerminalGenerator struct { SCMProvider *SCMProviderGenerator `json:"scmProvider,omitempty" protobuf:"bytes,4,name=scmProvider"` ClusterDecisionResource *DuckTypeGenerator `json:"clusterDecisionResource,omitempty" protobuf:"bytes,5,name=clusterDecisionResource"` PullRequest *PullRequestGenerator `json:"pullRequest,omitempty" protobuf:"bytes,6,name=pullRequest"` + Plugin *PluginGenerator `json:"plugin,omitempty" protobuf:"bytes,7,name=plugin"` + + // Selector allows to post-filter all generator. + Selector *metav1.LabelSelector `json:"selector,omitempty" protobuf:"bytes,8,name=selector"` } type ApplicationSetTerminalGenerators []ApplicationSetTerminalGenerator @@ -170,6 +251,8 @@ func (g ApplicationSetTerminalGenerators) toApplicationSetNestedGenerators() []A SCMProvider: terminalGenerator.SCMProvider, ClusterDecisionResource: terminalGenerator.ClusterDecisionResource, PullRequest: terminalGenerator.PullRequest, + Plugin: terminalGenerator.Plugin, + Selector: terminalGenerator.Selector, } } return nestedGenerators @@ -177,8 +260,10 @@ func (g ApplicationSetTerminalGenerators) toApplicationSetNestedGenerators() []A // ListGenerator include items info type ListGenerator struct { - Elements []apiextensionsv1.JSON `json:"elements" protobuf:"bytes,1,name=elements"` - Template ApplicationSetTemplate `json:"template,omitempty" protobuf:"bytes,2,name=template"` + // +kubebuilder:validation:Optional + Elements []apiextensionsv1.JSON `json:"elements" protobuf:"bytes,1,name=elements"` + Template ApplicationSetTemplate `json:"template,omitempty" protobuf:"bytes,2,name=template"` + ElementsYaml string `json:"elementsYaml,omitempty" protobuf:"bytes,3,opt,name=elementsYaml"` } // MatrixGenerator generates the cartesian product of two sets of parameters. The parameters are defined by two nested @@ -314,6 +399,9 @@ type GitGenerator struct { RequeueAfterSeconds *int64 `json:"requeueAfterSeconds,omitempty" protobuf:"bytes,5,name=requeueAfterSeconds"` Template ApplicationSetTemplate `json:"template,omitempty" protobuf:"bytes,6,name=template"` PathParamPrefix string `json:"pathParamPrefix,omitempty" protobuf:"bytes,7,name=pathParamPrefix"` + + // Values contains key/value pairs which are passed directly as parameters to the template + Values map[string]string `json:"values,omitempty" protobuf:"bytes,8,name=values"` } type GitDirectoryGeneratorItem struct { @@ -342,6 +430,26 @@ type SCMProviderGenerator struct { // Standard parameters. RequeueAfterSeconds *int64 `json:"requeueAfterSeconds,omitempty" protobuf:"varint,9,opt,name=requeueAfterSeconds"` Template ApplicationSetTemplate `json:"template,omitempty" protobuf:"bytes,10,opt,name=template"` + + // Values contains key/value pairs which are passed directly as parameters to the template + Values map[string]string `json:"values,omitempty" protobuf:"bytes,11,name=values"` + AWSCodeCommit *SCMProviderGeneratorAWSCodeCommit `json:"awsCodeCommit,omitempty" protobuf:"bytes,12,opt,name=awsCodeCommit"` + // If you add a new SCM provider, update CustomApiUrl below. +} + +func (g *SCMProviderGenerator) CustomApiUrl() string { + if g.Github != nil { + return g.Github.API + } else if g.Gitlab != nil { + return g.Gitlab.API + } else if g.Gitea != nil { + return g.Gitea.API + } else if g.BitbucketServer != nil { + return g.BitbucketServer.API + } else if g.AzureDevOps != nil { + return g.AzureDevOps.API + } + return "" } // SCMProviderGeneratorGitea defines a connection info specific to Gitea. @@ -384,6 +492,16 @@ type SCMProviderGeneratorGitlab struct { TokenRef *SecretRef `json:"tokenRef,omitempty" protobuf:"bytes,4,opt,name=tokenRef"` // Scan all branches instead of just the default branch. AllBranches bool `json:"allBranches,omitempty" protobuf:"varint,5,opt,name=allBranches"` + // Skips validating the SCM provider's TLS certificate - useful for self-signed certificates.; default: false + Insecure bool `json:"insecure,omitempty" protobuf:"varint,6,opt,name=insecure"` + // When recursing through subgroups, also include shared Projects (true) or scan only the subgroups under same path (false). Defaults to "true" + IncludeSharedProjects *bool `json:"includeSharedProjects,omitempty" protobuf:"varint,7,opt,name=includeSharedProjects"` + // Filter repos list based on Gitlab Topic. + Topic string `json:"topic,omitempty" protobuf:"bytes,8,opt,name=topic"` +} + +func (s *SCMProviderGeneratorGitlab) WillIncludeSharedProjects() bool { + return s.IncludeSharedProjects == nil || *s.IncludeSharedProjects } // SCMProviderGeneratorBitbucket defines connection info specific to Bitbucket Cloud (API version 2). @@ -424,6 +542,25 @@ type SCMProviderGeneratorAzureDevOps struct { AllBranches bool `json:"allBranches,omitempty" protobuf:"varint,9,opt,name=allBranches"` } +type TagFilter struct { + Key string `json:"key" protobuf:"bytes,1,opt,name=key"` + Value string `json:"value,omitempty" protobuf:"bytes,2,opt,name=value"` +} + +// SCMProviderGeneratorAWSCodeCommit defines connection info specific to AWS CodeCommit. +type SCMProviderGeneratorAWSCodeCommit struct { + // TagFilters provides the tag filter(s) for repo discovery + TagFilters []*TagFilter `json:"tagFilters,omitempty" protobuf:"bytes,1,opt,name=tagFilters"` + // Role provides the AWS IAM role to assume, for cross-account repo discovery + // if not provided, AppSet controller will use its pod/node identity to discover. + Role string `json:"role,omitempty" protobuf:"bytes,2,opt,name=role"` + // Region provides the AWS region to discover repos. + // if not provided, AppSet controller will infer the current region from environment. + Region string `json:"region,omitempty" protobuf:"bytes,3,opt,name=region"` + // Scan all branches instead of just the default branch. + AllBranches bool `json:"allBranches,omitempty" protobuf:"varint,4,opt,name=allBranches"` +} + // SCMProviderGeneratorFilter is a single repository filter. // If multiple filter types are set on a single struct, they will be AND'd together. All filters must // pass for a repo to be included. @@ -450,11 +587,37 @@ type PullRequestGenerator struct { // Filters for which pull requests should be considered. Filters []PullRequestGeneratorFilter `json:"filters,omitempty" protobuf:"bytes,5,rep,name=filters"` // Standard parameters. - RequeueAfterSeconds *int64 `json:"requeueAfterSeconds,omitempty" protobuf:"varint,6,opt,name=requeueAfterSeconds"` - Template ApplicationSetTemplate `json:"template,omitempty" protobuf:"bytes,7,opt,name=template"` + RequeueAfterSeconds *int64 `json:"requeueAfterSeconds,omitempty" protobuf:"varint,6,opt,name=requeueAfterSeconds"` + Template ApplicationSetTemplate `json:"template,omitempty" protobuf:"bytes,7,opt,name=template"` + Bitbucket *PullRequestGeneratorBitbucket `json:"bitbucket,omitempty" protobuf:"bytes,8,opt,name=bitbucket"` + // Additional provider to use and config for it. + AzureDevOps *PullRequestGeneratorAzureDevOps `json:"azuredevops,omitempty" protobuf:"bytes,9,opt,name=azuredevops"` + // If you add a new SCM provider, update CustomApiUrl below. } -// PullRequestGenerator defines connection info specific to Gitea. +func (p *PullRequestGenerator) CustomApiUrl() string { + if p.Github != nil { + return p.Github.API + } + if p.GitLab != nil { + return p.GitLab.API + } + if p.Gitea != nil { + return p.Gitea.API + } + if p.BitbucketServer != nil { + return p.BitbucketServer.API + } + if p.Bitbucket != nil { + return p.Bitbucket.API + } + if p.AzureDevOps != nil { + return p.AzureDevOps.API + } + return "" +} + +// PullRequestGeneratorGitea defines connection info specific to Gitea. type PullRequestGeneratorGitea struct { // Gitea org or user to scan. Required. Owner string `json:"owner" protobuf:"bytes,1,opt,name=owner"` @@ -468,6 +631,22 @@ type PullRequestGeneratorGitea struct { Insecure bool `json:"insecure,omitempty" protobuf:"varint,5,opt,name=insecure"` } +// PullRequestGeneratorAzureDevOps defines connection info specific to AzureDevOps. +type PullRequestGeneratorAzureDevOps struct { + // Azure DevOps org to scan. Required. + Organization string `json:"organization" protobuf:"bytes,1,opt,name=organization"` + // Azure DevOps project name to scan. Required. + Project string `json:"project" protobuf:"bytes,2,opt,name=project"` + // Azure DevOps repo name to scan. Required. + Repo string `json:"repo" protobuf:"bytes,3,opt,name=repo"` + // The Azure DevOps API URL to talk to. If blank, use https://dev.azure.com/. + API string `json:"api,omitempty" protobuf:"bytes,4,opt,name=api"` + // Authentication token reference. + TokenRef *SecretRef `json:"tokenRef,omitempty" protobuf:"bytes,5,opt,name=tokenRef"` + // Labels is used to filter the PRs that you want to target + Labels []string `json:"labels,omitempty" protobuf:"bytes,6,rep,name=labels"` +} + // PullRequestGenerator defines connection info specific to GitHub. type PullRequestGeneratorGithub struct { // GitHub org or user to scan. Required. @@ -496,9 +675,11 @@ type PullRequestGeneratorGitLab struct { Labels []string `json:"labels,omitempty" protobuf:"bytes,4,rep,name=labels"` // PullRequestState is an additional MRs filter to get only those with a certain state. Default: "" (all states) PullRequestState string `json:"pullRequestState,omitempty" protobuf:"bytes,5,rep,name=pullRequestState"` + // Skips validating the SCM provider's TLS certificate - useful for self-signed certificates.; default: false + Insecure bool `json:"insecure,omitempty" protobuf:"varint,6,opt,name=insecure"` } -// PullRequestGenerator defines connection info specific to BitbucketServer. +// PullRequestGeneratorBitbucketServer defines connection info specific to BitbucketServer. type PullRequestGeneratorBitbucketServer struct { // Project to scan. Required. Project string `json:"project" protobuf:"bytes,1,opt,name=project"` @@ -510,6 +691,26 @@ type PullRequestGeneratorBitbucketServer struct { BasicAuth *BasicAuthBitbucketServer `json:"basicAuth,omitempty" protobuf:"bytes,4,opt,name=basicAuth"` } +// PullRequestGeneratorBitbucket defines connection info specific to Bitbucket. +type PullRequestGeneratorBitbucket struct { + // Workspace to scan. Required. + Owner string `json:"owner" protobuf:"bytes,1,opt,name=owner"` + // Repo name to scan. Required. + Repo string `json:"repo" protobuf:"bytes,2,opt,name=repo"` + // The Bitbucket REST API URL to talk to. If blank, uses https://api.bitbucket.org/2.0. + API string `json:"api,omitempty" protobuf:"bytes,3,opt,name=api"` + // Credentials for Basic auth + BasicAuth *BasicAuthBitbucketServer `json:"basicAuth,omitempty" protobuf:"bytes,4,opt,name=basicAuth"` + // Credentials for AppToken (Bearer auth) + BearerToken *BearerTokenBitbucketCloud `json:"bearerToken,omitempty" protobuf:"bytes,5,opt,name=bearerToken"` +} + +// BearerTokenBitbucketCloud defines the Bearer token for BitBucket AppToken auth. +type BearerTokenBitbucketCloud struct { + // Password (or personal access token) reference. + TokenRef *SecretRef `json:"tokenRef" protobuf:"bytes,1,opt,name=tokenRef"` +} + // BasicAuthBitbucketServer defines the username/(password or personal access token) for Basic auth. type BasicAuthBitbucketServer struct { // Username for Basic auth @@ -522,7 +723,34 @@ type BasicAuthBitbucketServer struct { // If multiple filter types are set on a single struct, they will be AND'd together. All filters must // pass for a pull request to be included. type PullRequestGeneratorFilter struct { - BranchMatch *string `json:"branchMatch,omitempty" protobuf:"bytes,1,opt,name=branchMatch"` + BranchMatch *string `json:"branchMatch,omitempty" protobuf:"bytes,1,opt,name=branchMatch"` + TargetBranchMatch *string `json:"targetBranchMatch,omitempty" protobuf:"bytes,2,opt,name=targetBranchMatch"` +} + +type PluginConfigMapRef struct { + // Name of the ConfigMap + Name string `json:"name" protobuf:"bytes,1,opt,name=name"` +} + +type PluginParameters map[string]apiextensionsv1.JSON + +type PluginInput struct { + // Parameters contains the information to pass to the plugin. It is a map. The keys must be strings, and the + // values can be any type. + Parameters PluginParameters `json:"parameters,omitempty" protobuf:"bytes,1,name=parameters"` +} + +// PluginGenerator defines connection info specific to Plugin. +type PluginGenerator struct { + ConfigMapRef PluginConfigMapRef `json:"configMapRef" protobuf:"bytes,1,name=configMapRef"` + Input PluginInput `json:"input,omitempty" protobuf:"bytes,2,name=input"` + // RequeueAfterSeconds determines how long the ApplicationSet controller will wait before reconciling the ApplicationSet again. + RequeueAfterSeconds *int64 `json:"requeueAfterSeconds,omitempty" protobuf:"varint,3,opt,name=requeueAfterSeconds"` + Template ApplicationSetTemplate `json:"template,omitempty" protobuf:"bytes,4,name=template"` + + // Values contains key/value pairs which are passed directly as parameters to the template. These values will not be + // sent as parameters to the plugin. + Values map[string]string `json:"values,omitempty" protobuf:"bytes,5,name=values"` } // ApplicationSetStatus defines the observed state of ApplicationSet @@ -602,7 +830,9 @@ type ApplicationSetApplicationStatus struct { // Message contains human-readable message indicating details about the status Message string `json:"message" protobuf:"bytes,3,opt,name=message"` // Status contains the AppSet's perceived status of the managed Application resource: (Waiting, Pending, Progressing, Healthy) - Status string `json:"status" protobuf:"bytes,5,opt,name=status"` + Status string `json:"status" protobuf:"bytes,4,opt,name=status"` + // Step tracks which step this Application should be updated in + Step string `json:"step" protobuf:"bytes,5,opt,name=step"` } // ApplicationSetList contains a list of ApplicationSet @@ -673,3 +903,14 @@ func (status *ApplicationSetStatus) SetApplicationStatus(newStatus ApplicationSe } status.ApplicationStatus = append(status.ApplicationStatus, newStatus) } + +// QualifiedName returns the full qualified name of the applicationset, including +// the name of the namespace it is created in delimited by a forward slash, +// i.e. / +func (a *ApplicationSet) QualifiedName() string { + if a.Namespace == "" { + return a.Name + } else { + return a.Namespace + "/" + a.Name + } +} diff --git a/pkg/apis/application/v1alpha1/applicationset_types_test.go b/pkg/apis/application/v1alpha1/applicationset_types_test.go index 67fc502470a06..282cc1ca9a423 100644 --- a/pkg/apis/application/v1alpha1/applicationset_types_test.go +++ b/pkg/apis/application/v1alpha1/applicationset_types_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/pointer" ) func testAppSetCond(t ApplicationSetConditionType, msg string, lastTransitionTime *metav1.Time, status ApplicationSetConditionStatus, reason string) ApplicationSetCondition { @@ -38,6 +39,42 @@ func newTestAppSet(name, namespace, repo string) *ApplicationSet { return a } +func TestApplicationsSyncPolicy(t *testing.T) { + assert.False(t, ApplicationsSyncPolicyCreateOnly.AllowDelete()) + assert.False(t, ApplicationsSyncPolicyCreateOnly.AllowUpdate()) + + assert.False(t, ApplicationsSyncPolicyCreateUpdate.AllowDelete()) + assert.True(t, ApplicationsSyncPolicyCreateUpdate.AllowUpdate()) + + assert.True(t, ApplicationsSyncPolicySync.AllowDelete()) + assert.True(t, ApplicationsSyncPolicySync.AllowUpdate()) +} + +func TestApplicationSetRBACName(t *testing.T) { + testRepo := "https://github.com/org/repo" + + t.Run("Test RBAC name with namespace", func(t *testing.T) { + namespace := "guestbook" + a := newTestAppSet("test-appset", namespace, testRepo) + a.Spec.Template.Spec.Project = "test" + assert.Equal(t, "test/guestbook/test-appset", a.RBACName("argocd")) + }) + + t.Run("Test RBAC name default ns", func(t *testing.T) { + namespace := "argocd" + a := newTestAppSet("test-appset", namespace, testRepo) + a.Spec.Template.Spec.Project = "test" + assert.Equal(t, "test/test-appset", a.RBACName("argocd")) + }) + + t.Run("Test RBAC no ns", func(t *testing.T) { + a := newTestAppSet("test-appset", "", testRepo) + a.Spec.Template.Spec.Project = "test" + assert.Equal(t, "test/test-appset", a.RBACName("argocd")) + }) + +} + func TestApplicationSetSetConditions(t *testing.T) { fiveMinsAgo := &metav1.Time{Time: time.Now().Add(-5 * time.Minute)} tenMinsAgo := &metav1.Time{Time: time.Now().Add(-10 * time.Minute)} @@ -131,3 +168,14 @@ func assertAppSetConditions(t *testing.T, expected []ApplicationSetCondition, ac assert.Equal(t, expected[i].Message, actual[i].Message) } } + +func TestSCMProviderGeneratorGitlab_WillIncludeSharedProjects(t *testing.T) { + settings := SCMProviderGeneratorGitlab{} + assert.True(t, settings.WillIncludeSharedProjects()) + + settings.IncludeSharedProjects = pointer.Bool(false) + assert.False(t, settings.WillIncludeSharedProjects()) + + 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 6eb480af30f11..f6a253d23ed7d 100644 --- a/pkg/apis/application/v1alpha1/generated.pb.go +++ b/pkg/apis/application/v1alpha1/generated.pb.go @@ -17,6 +17,7 @@ import ( v12 "k8s.io/api/core/v1" v11 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" math "math" math_bits "math/bits" @@ -318,10 +319,38 @@ func (m *ApplicationMatchExpression) XXX_DiscardUnknown() { var xxx_messageInfo_ApplicationMatchExpression proto.InternalMessageInfo +func (m *ApplicationPreservedFields) Reset() { *m = ApplicationPreservedFields{} } +func (*ApplicationPreservedFields) ProtoMessage() {} +func (*ApplicationPreservedFields) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{10} +} +func (m *ApplicationPreservedFields) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ApplicationPreservedFields) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *ApplicationPreservedFields) XXX_Merge(src proto.Message) { + xxx_messageInfo_ApplicationPreservedFields.Merge(m, src) +} +func (m *ApplicationPreservedFields) XXX_Size() int { + return m.Size() +} +func (m *ApplicationPreservedFields) XXX_DiscardUnknown() { + xxx_messageInfo_ApplicationPreservedFields.DiscardUnknown(m) +} + +var xxx_messageInfo_ApplicationPreservedFields proto.InternalMessageInfo + func (m *ApplicationSet) Reset() { *m = ApplicationSet{} } func (*ApplicationSet) ProtoMessage() {} func (*ApplicationSet) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{10} + return fileDescriptor_030104ce3b95bcac, []int{11} } func (m *ApplicationSet) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -349,7 +378,7 @@ var xxx_messageInfo_ApplicationSet proto.InternalMessageInfo func (m *ApplicationSetApplicationStatus) Reset() { *m = ApplicationSetApplicationStatus{} } func (*ApplicationSetApplicationStatus) ProtoMessage() {} func (*ApplicationSetApplicationStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{11} + return fileDescriptor_030104ce3b95bcac, []int{12} } func (m *ApplicationSetApplicationStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -377,7 +406,7 @@ var xxx_messageInfo_ApplicationSetApplicationStatus proto.InternalMessageInfo func (m *ApplicationSetCondition) Reset() { *m = ApplicationSetCondition{} } func (*ApplicationSetCondition) ProtoMessage() {} func (*ApplicationSetCondition) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{12} + return fileDescriptor_030104ce3b95bcac, []int{13} } func (m *ApplicationSetCondition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -405,7 +434,7 @@ var xxx_messageInfo_ApplicationSetCondition proto.InternalMessageInfo func (m *ApplicationSetGenerator) Reset() { *m = ApplicationSetGenerator{} } func (*ApplicationSetGenerator) ProtoMessage() {} func (*ApplicationSetGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{13} + return fileDescriptor_030104ce3b95bcac, []int{14} } func (m *ApplicationSetGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -433,7 +462,7 @@ var xxx_messageInfo_ApplicationSetGenerator proto.InternalMessageInfo func (m *ApplicationSetList) Reset() { *m = ApplicationSetList{} } func (*ApplicationSetList) ProtoMessage() {} func (*ApplicationSetList) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{14} + return fileDescriptor_030104ce3b95bcac, []int{15} } func (m *ApplicationSetList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -461,7 +490,7 @@ var xxx_messageInfo_ApplicationSetList proto.InternalMessageInfo func (m *ApplicationSetNestedGenerator) Reset() { *m = ApplicationSetNestedGenerator{} } func (*ApplicationSetNestedGenerator) ProtoMessage() {} func (*ApplicationSetNestedGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{15} + return fileDescriptor_030104ce3b95bcac, []int{16} } func (m *ApplicationSetNestedGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -486,10 +515,40 @@ func (m *ApplicationSetNestedGenerator) XXX_DiscardUnknown() { var xxx_messageInfo_ApplicationSetNestedGenerator proto.InternalMessageInfo +func (m *ApplicationSetResourceIgnoreDifferences) Reset() { + *m = ApplicationSetResourceIgnoreDifferences{} +} +func (*ApplicationSetResourceIgnoreDifferences) ProtoMessage() {} +func (*ApplicationSetResourceIgnoreDifferences) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{17} +} +func (m *ApplicationSetResourceIgnoreDifferences) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ApplicationSetResourceIgnoreDifferences) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *ApplicationSetResourceIgnoreDifferences) XXX_Merge(src proto.Message) { + xxx_messageInfo_ApplicationSetResourceIgnoreDifferences.Merge(m, src) +} +func (m *ApplicationSetResourceIgnoreDifferences) XXX_Size() int { + return m.Size() +} +func (m *ApplicationSetResourceIgnoreDifferences) XXX_DiscardUnknown() { + xxx_messageInfo_ApplicationSetResourceIgnoreDifferences.DiscardUnknown(m) +} + +var xxx_messageInfo_ApplicationSetResourceIgnoreDifferences proto.InternalMessageInfo + func (m *ApplicationSetRolloutStep) Reset() { *m = ApplicationSetRolloutStep{} } func (*ApplicationSetRolloutStep) ProtoMessage() {} func (*ApplicationSetRolloutStep) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{16} + return fileDescriptor_030104ce3b95bcac, []int{18} } func (m *ApplicationSetRolloutStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -517,7 +576,7 @@ var xxx_messageInfo_ApplicationSetRolloutStep proto.InternalMessageInfo func (m *ApplicationSetRolloutStrategy) Reset() { *m = ApplicationSetRolloutStrategy{} } func (*ApplicationSetRolloutStrategy) ProtoMessage() {} func (*ApplicationSetRolloutStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{17} + return fileDescriptor_030104ce3b95bcac, []int{19} } func (m *ApplicationSetRolloutStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -545,7 +604,7 @@ var xxx_messageInfo_ApplicationSetRolloutStrategy proto.InternalMessageInfo func (m *ApplicationSetSpec) Reset() { *m = ApplicationSetSpec{} } func (*ApplicationSetSpec) ProtoMessage() {} func (*ApplicationSetSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{18} + return fileDescriptor_030104ce3b95bcac, []int{20} } func (m *ApplicationSetSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -573,7 +632,7 @@ var xxx_messageInfo_ApplicationSetSpec proto.InternalMessageInfo func (m *ApplicationSetStatus) Reset() { *m = ApplicationSetStatus{} } func (*ApplicationSetStatus) ProtoMessage() {} func (*ApplicationSetStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{19} + return fileDescriptor_030104ce3b95bcac, []int{21} } func (m *ApplicationSetStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -601,7 +660,7 @@ var xxx_messageInfo_ApplicationSetStatus proto.InternalMessageInfo func (m *ApplicationSetStrategy) Reset() { *m = ApplicationSetStrategy{} } func (*ApplicationSetStrategy) ProtoMessage() {} func (*ApplicationSetStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{20} + return fileDescriptor_030104ce3b95bcac, []int{22} } func (m *ApplicationSetStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -629,7 +688,7 @@ var xxx_messageInfo_ApplicationSetStrategy proto.InternalMessageInfo func (m *ApplicationSetSyncPolicy) Reset() { *m = ApplicationSetSyncPolicy{} } func (*ApplicationSetSyncPolicy) ProtoMessage() {} func (*ApplicationSetSyncPolicy) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{21} + return fileDescriptor_030104ce3b95bcac, []int{23} } func (m *ApplicationSetSyncPolicy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -657,7 +716,7 @@ var xxx_messageInfo_ApplicationSetSyncPolicy proto.InternalMessageInfo func (m *ApplicationSetTemplate) Reset() { *m = ApplicationSetTemplate{} } func (*ApplicationSetTemplate) ProtoMessage() {} func (*ApplicationSetTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{22} + return fileDescriptor_030104ce3b95bcac, []int{24} } func (m *ApplicationSetTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -685,7 +744,7 @@ var xxx_messageInfo_ApplicationSetTemplate proto.InternalMessageInfo func (m *ApplicationSetTemplateMeta) Reset() { *m = ApplicationSetTemplateMeta{} } func (*ApplicationSetTemplateMeta) ProtoMessage() {} func (*ApplicationSetTemplateMeta) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{23} + return fileDescriptor_030104ce3b95bcac, []int{25} } func (m *ApplicationSetTemplateMeta) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -713,7 +772,7 @@ var xxx_messageInfo_ApplicationSetTemplateMeta proto.InternalMessageInfo func (m *ApplicationSetTerminalGenerator) Reset() { *m = ApplicationSetTerminalGenerator{} } func (*ApplicationSetTerminalGenerator) ProtoMessage() {} func (*ApplicationSetTerminalGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{24} + return fileDescriptor_030104ce3b95bcac, []int{26} } func (m *ApplicationSetTerminalGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -741,7 +800,7 @@ var xxx_messageInfo_ApplicationSetTerminalGenerator proto.InternalMessageInfo func (m *ApplicationSource) Reset() { *m = ApplicationSource{} } func (*ApplicationSource) ProtoMessage() {} func (*ApplicationSource) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{25} + return fileDescriptor_030104ce3b95bcac, []int{27} } func (m *ApplicationSource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -769,7 +828,7 @@ var xxx_messageInfo_ApplicationSource proto.InternalMessageInfo func (m *ApplicationSourceDirectory) Reset() { *m = ApplicationSourceDirectory{} } func (*ApplicationSourceDirectory) ProtoMessage() {} func (*ApplicationSourceDirectory) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{26} + return fileDescriptor_030104ce3b95bcac, []int{28} } func (m *ApplicationSourceDirectory) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -797,7 +856,7 @@ var xxx_messageInfo_ApplicationSourceDirectory proto.InternalMessageInfo func (m *ApplicationSourceHelm) Reset() { *m = ApplicationSourceHelm{} } func (*ApplicationSourceHelm) ProtoMessage() {} func (*ApplicationSourceHelm) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{27} + return fileDescriptor_030104ce3b95bcac, []int{29} } func (m *ApplicationSourceHelm) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -825,7 +884,7 @@ var xxx_messageInfo_ApplicationSourceHelm proto.InternalMessageInfo func (m *ApplicationSourceJsonnet) Reset() { *m = ApplicationSourceJsonnet{} } func (*ApplicationSourceJsonnet) ProtoMessage() {} func (*ApplicationSourceJsonnet) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{28} + return fileDescriptor_030104ce3b95bcac, []int{30} } func (m *ApplicationSourceJsonnet) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -853,7 +912,7 @@ var xxx_messageInfo_ApplicationSourceJsonnet proto.InternalMessageInfo func (m *ApplicationSourceKustomize) Reset() { *m = ApplicationSourceKustomize{} } func (*ApplicationSourceKustomize) ProtoMessage() {} func (*ApplicationSourceKustomize) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{29} + return fileDescriptor_030104ce3b95bcac, []int{31} } func (m *ApplicationSourceKustomize) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -881,7 +940,7 @@ var xxx_messageInfo_ApplicationSourceKustomize proto.InternalMessageInfo func (m *ApplicationSourcePlugin) Reset() { *m = ApplicationSourcePlugin{} } func (*ApplicationSourcePlugin) ProtoMessage() {} func (*ApplicationSourcePlugin) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{30} + return fileDescriptor_030104ce3b95bcac, []int{32} } func (m *ApplicationSourcePlugin) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -909,7 +968,7 @@ var xxx_messageInfo_ApplicationSourcePlugin proto.InternalMessageInfo func (m *ApplicationSourcePluginParameter) Reset() { *m = ApplicationSourcePluginParameter{} } func (*ApplicationSourcePluginParameter) ProtoMessage() {} func (*ApplicationSourcePluginParameter) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{31} + return fileDescriptor_030104ce3b95bcac, []int{33} } func (m *ApplicationSourcePluginParameter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -937,7 +996,7 @@ var xxx_messageInfo_ApplicationSourcePluginParameter proto.InternalMessageInfo func (m *ApplicationSpec) Reset() { *m = ApplicationSpec{} } func (*ApplicationSpec) ProtoMessage() {} func (*ApplicationSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{32} + return fileDescriptor_030104ce3b95bcac, []int{34} } func (m *ApplicationSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -965,7 +1024,7 @@ var xxx_messageInfo_ApplicationSpec proto.InternalMessageInfo func (m *ApplicationStatus) Reset() { *m = ApplicationStatus{} } func (*ApplicationStatus) ProtoMessage() {} func (*ApplicationStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{33} + return fileDescriptor_030104ce3b95bcac, []int{35} } func (m *ApplicationStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -993,7 +1052,7 @@ var xxx_messageInfo_ApplicationStatus proto.InternalMessageInfo func (m *ApplicationSummary) Reset() { *m = ApplicationSummary{} } func (*ApplicationSummary) ProtoMessage() {} func (*ApplicationSummary) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{34} + return fileDescriptor_030104ce3b95bcac, []int{36} } func (m *ApplicationSummary) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1021,7 +1080,7 @@ var xxx_messageInfo_ApplicationSummary proto.InternalMessageInfo func (m *ApplicationTree) Reset() { *m = ApplicationTree{} } func (*ApplicationTree) ProtoMessage() {} func (*ApplicationTree) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{35} + return fileDescriptor_030104ce3b95bcac, []int{37} } func (m *ApplicationTree) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1049,7 +1108,7 @@ var xxx_messageInfo_ApplicationTree proto.InternalMessageInfo func (m *ApplicationWatchEvent) Reset() { *m = ApplicationWatchEvent{} } func (*ApplicationWatchEvent) ProtoMessage() {} func (*ApplicationWatchEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{36} + return fileDescriptor_030104ce3b95bcac, []int{38} } func (m *ApplicationWatchEvent) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1077,7 +1136,7 @@ var xxx_messageInfo_ApplicationWatchEvent proto.InternalMessageInfo func (m *Backoff) Reset() { *m = Backoff{} } func (*Backoff) ProtoMessage() {} func (*Backoff) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{37} + return fileDescriptor_030104ce3b95bcac, []int{39} } func (m *Backoff) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1105,7 +1164,7 @@ var xxx_messageInfo_Backoff proto.InternalMessageInfo func (m *BasicAuthBitbucketServer) Reset() { *m = BasicAuthBitbucketServer{} } func (*BasicAuthBitbucketServer) ProtoMessage() {} func (*BasicAuthBitbucketServer) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{38} + return fileDescriptor_030104ce3b95bcac, []int{40} } func (m *BasicAuthBitbucketServer) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1130,10 +1189,66 @@ func (m *BasicAuthBitbucketServer) XXX_DiscardUnknown() { var xxx_messageInfo_BasicAuthBitbucketServer proto.InternalMessageInfo +func (m *BearerTokenBitbucketCloud) Reset() { *m = BearerTokenBitbucketCloud{} } +func (*BearerTokenBitbucketCloud) ProtoMessage() {} +func (*BearerTokenBitbucketCloud) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{41} +} +func (m *BearerTokenBitbucketCloud) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *BearerTokenBitbucketCloud) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *BearerTokenBitbucketCloud) XXX_Merge(src proto.Message) { + xxx_messageInfo_BearerTokenBitbucketCloud.Merge(m, src) +} +func (m *BearerTokenBitbucketCloud) XXX_Size() int { + return m.Size() +} +func (m *BearerTokenBitbucketCloud) XXX_DiscardUnknown() { + xxx_messageInfo_BearerTokenBitbucketCloud.DiscardUnknown(m) +} + +var xxx_messageInfo_BearerTokenBitbucketCloud proto.InternalMessageInfo + +func (m *ChartDetails) Reset() { *m = ChartDetails{} } +func (*ChartDetails) ProtoMessage() {} +func (*ChartDetails) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{42} +} +func (m *ChartDetails) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ChartDetails) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *ChartDetails) XXX_Merge(src proto.Message) { + xxx_messageInfo_ChartDetails.Merge(m, src) +} +func (m *ChartDetails) XXX_Size() int { + return m.Size() +} +func (m *ChartDetails) XXX_DiscardUnknown() { + xxx_messageInfo_ChartDetails.DiscardUnknown(m) +} + +var xxx_messageInfo_ChartDetails proto.InternalMessageInfo + func (m *Cluster) Reset() { *m = Cluster{} } func (*Cluster) ProtoMessage() {} func (*Cluster) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{39} + return fileDescriptor_030104ce3b95bcac, []int{43} } func (m *Cluster) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1161,7 +1276,7 @@ var xxx_messageInfo_Cluster proto.InternalMessageInfo func (m *ClusterCacheInfo) Reset() { *m = ClusterCacheInfo{} } func (*ClusterCacheInfo) ProtoMessage() {} func (*ClusterCacheInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{40} + return fileDescriptor_030104ce3b95bcac, []int{44} } func (m *ClusterCacheInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1189,7 +1304,7 @@ var xxx_messageInfo_ClusterCacheInfo proto.InternalMessageInfo func (m *ClusterConfig) Reset() { *m = ClusterConfig{} } func (*ClusterConfig) ProtoMessage() {} func (*ClusterConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{41} + return fileDescriptor_030104ce3b95bcac, []int{45} } func (m *ClusterConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1217,7 +1332,7 @@ var xxx_messageInfo_ClusterConfig proto.InternalMessageInfo func (m *ClusterGenerator) Reset() { *m = ClusterGenerator{} } func (*ClusterGenerator) ProtoMessage() {} func (*ClusterGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{42} + return fileDescriptor_030104ce3b95bcac, []int{46} } func (m *ClusterGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1245,7 +1360,7 @@ var xxx_messageInfo_ClusterGenerator proto.InternalMessageInfo func (m *ClusterInfo) Reset() { *m = ClusterInfo{} } func (*ClusterInfo) ProtoMessage() {} func (*ClusterInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{43} + return fileDescriptor_030104ce3b95bcac, []int{47} } func (m *ClusterInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1273,7 +1388,7 @@ var xxx_messageInfo_ClusterInfo proto.InternalMessageInfo func (m *ClusterList) Reset() { *m = ClusterList{} } func (*ClusterList) ProtoMessage() {} func (*ClusterList) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{44} + return fileDescriptor_030104ce3b95bcac, []int{48} } func (m *ClusterList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1301,7 +1416,7 @@ var xxx_messageInfo_ClusterList proto.InternalMessageInfo func (m *Command) Reset() { *m = Command{} } func (*Command) ProtoMessage() {} func (*Command) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{45} + return fileDescriptor_030104ce3b95bcac, []int{49} } func (m *Command) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1329,7 +1444,7 @@ var xxx_messageInfo_Command proto.InternalMessageInfo func (m *ComparedTo) Reset() { *m = ComparedTo{} } func (*ComparedTo) ProtoMessage() {} func (*ComparedTo) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{46} + return fileDescriptor_030104ce3b95bcac, []int{50} } func (m *ComparedTo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1357,7 +1472,7 @@ var xxx_messageInfo_ComparedTo proto.InternalMessageInfo func (m *ComponentParameter) Reset() { *m = ComponentParameter{} } func (*ComponentParameter) ProtoMessage() {} func (*ComponentParameter) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{47} + return fileDescriptor_030104ce3b95bcac, []int{51} } func (m *ComponentParameter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1385,7 +1500,7 @@ var xxx_messageInfo_ComponentParameter proto.InternalMessageInfo func (m *ConfigManagementPlugin) Reset() { *m = ConfigManagementPlugin{} } func (*ConfigManagementPlugin) ProtoMessage() {} func (*ConfigManagementPlugin) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{48} + return fileDescriptor_030104ce3b95bcac, []int{52} } func (m *ConfigManagementPlugin) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1413,7 +1528,7 @@ var xxx_messageInfo_ConfigManagementPlugin proto.InternalMessageInfo func (m *ConnectionState) Reset() { *m = ConnectionState{} } func (*ConnectionState) ProtoMessage() {} func (*ConnectionState) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{49} + return fileDescriptor_030104ce3b95bcac, []int{53} } func (m *ConnectionState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1441,7 +1556,7 @@ var xxx_messageInfo_ConnectionState proto.InternalMessageInfo func (m *DuckTypeGenerator) Reset() { *m = DuckTypeGenerator{} } func (*DuckTypeGenerator) ProtoMessage() {} func (*DuckTypeGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{50} + return fileDescriptor_030104ce3b95bcac, []int{54} } func (m *DuckTypeGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1469,7 +1584,7 @@ var xxx_messageInfo_DuckTypeGenerator proto.InternalMessageInfo func (m *EnvEntry) Reset() { *m = EnvEntry{} } func (*EnvEntry) ProtoMessage() {} func (*EnvEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{51} + return fileDescriptor_030104ce3b95bcac, []int{55} } func (m *EnvEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1497,7 +1612,7 @@ var xxx_messageInfo_EnvEntry proto.InternalMessageInfo func (m *ExecProviderConfig) Reset() { *m = ExecProviderConfig{} } func (*ExecProviderConfig) ProtoMessage() {} func (*ExecProviderConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{52} + return fileDescriptor_030104ce3b95bcac, []int{56} } func (m *ExecProviderConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1525,7 +1640,7 @@ var xxx_messageInfo_ExecProviderConfig proto.InternalMessageInfo func (m *GitDirectoryGeneratorItem) Reset() { *m = GitDirectoryGeneratorItem{} } func (*GitDirectoryGeneratorItem) ProtoMessage() {} func (*GitDirectoryGeneratorItem) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{53} + return fileDescriptor_030104ce3b95bcac, []int{57} } func (m *GitDirectoryGeneratorItem) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1553,7 +1668,7 @@ var xxx_messageInfo_GitDirectoryGeneratorItem proto.InternalMessageInfo func (m *GitFileGeneratorItem) Reset() { *m = GitFileGeneratorItem{} } func (*GitFileGeneratorItem) ProtoMessage() {} func (*GitFileGeneratorItem) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{54} + return fileDescriptor_030104ce3b95bcac, []int{58} } func (m *GitFileGeneratorItem) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1581,7 +1696,7 @@ var xxx_messageInfo_GitFileGeneratorItem proto.InternalMessageInfo func (m *GitGenerator) Reset() { *m = GitGenerator{} } func (*GitGenerator) ProtoMessage() {} func (*GitGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{55} + return fileDescriptor_030104ce3b95bcac, []int{59} } func (m *GitGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1609,7 +1724,7 @@ var xxx_messageInfo_GitGenerator proto.InternalMessageInfo func (m *GnuPGPublicKey) Reset() { *m = GnuPGPublicKey{} } func (*GnuPGPublicKey) ProtoMessage() {} func (*GnuPGPublicKey) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{56} + return fileDescriptor_030104ce3b95bcac, []int{60} } func (m *GnuPGPublicKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1637,7 +1752,7 @@ var xxx_messageInfo_GnuPGPublicKey proto.InternalMessageInfo func (m *GnuPGPublicKeyList) Reset() { *m = GnuPGPublicKeyList{} } func (*GnuPGPublicKeyList) ProtoMessage() {} func (*GnuPGPublicKeyList) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{57} + return fileDescriptor_030104ce3b95bcac, []int{61} } func (m *GnuPGPublicKeyList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1665,7 +1780,7 @@ var xxx_messageInfo_GnuPGPublicKeyList proto.InternalMessageInfo func (m *HealthStatus) Reset() { *m = HealthStatus{} } func (*HealthStatus) ProtoMessage() {} func (*HealthStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{58} + return fileDescriptor_030104ce3b95bcac, []int{62} } func (m *HealthStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1693,7 +1808,7 @@ var xxx_messageInfo_HealthStatus proto.InternalMessageInfo func (m *HelmFileParameter) Reset() { *m = HelmFileParameter{} } func (*HelmFileParameter) ProtoMessage() {} func (*HelmFileParameter) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{59} + return fileDescriptor_030104ce3b95bcac, []int{63} } func (m *HelmFileParameter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1721,7 +1836,7 @@ var xxx_messageInfo_HelmFileParameter proto.InternalMessageInfo func (m *HelmOptions) Reset() { *m = HelmOptions{} } func (*HelmOptions) ProtoMessage() {} func (*HelmOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{60} + return fileDescriptor_030104ce3b95bcac, []int{64} } func (m *HelmOptions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1749,7 +1864,7 @@ var xxx_messageInfo_HelmOptions proto.InternalMessageInfo func (m *HelmParameter) Reset() { *m = HelmParameter{} } func (*HelmParameter) ProtoMessage() {} func (*HelmParameter) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{61} + return fileDescriptor_030104ce3b95bcac, []int{65} } func (m *HelmParameter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1777,7 +1892,7 @@ var xxx_messageInfo_HelmParameter proto.InternalMessageInfo func (m *HostInfo) Reset() { *m = HostInfo{} } func (*HostInfo) ProtoMessage() {} func (*HostInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{62} + return fileDescriptor_030104ce3b95bcac, []int{66} } func (m *HostInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1805,7 +1920,7 @@ var xxx_messageInfo_HostInfo proto.InternalMessageInfo func (m *HostResourceInfo) Reset() { *m = HostResourceInfo{} } func (*HostResourceInfo) ProtoMessage() {} func (*HostResourceInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{63} + return fileDescriptor_030104ce3b95bcac, []int{67} } func (m *HostResourceInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1833,7 +1948,7 @@ var xxx_messageInfo_HostResourceInfo proto.InternalMessageInfo func (m *Info) Reset() { *m = Info{} } func (*Info) ProtoMessage() {} func (*Info) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{64} + return fileDescriptor_030104ce3b95bcac, []int{68} } func (m *Info) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1861,7 +1976,7 @@ var xxx_messageInfo_Info proto.InternalMessageInfo func (m *InfoItem) Reset() { *m = InfoItem{} } func (*InfoItem) ProtoMessage() {} func (*InfoItem) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{65} + return fileDescriptor_030104ce3b95bcac, []int{69} } func (m *InfoItem) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1889,7 +2004,7 @@ var xxx_messageInfo_InfoItem proto.InternalMessageInfo func (m *JWTToken) Reset() { *m = JWTToken{} } func (*JWTToken) ProtoMessage() {} func (*JWTToken) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{66} + return fileDescriptor_030104ce3b95bcac, []int{70} } func (m *JWTToken) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1917,7 +2032,7 @@ var xxx_messageInfo_JWTToken proto.InternalMessageInfo func (m *JWTTokens) Reset() { *m = JWTTokens{} } func (*JWTTokens) ProtoMessage() {} func (*JWTTokens) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{67} + return fileDescriptor_030104ce3b95bcac, []int{71} } func (m *JWTTokens) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1945,7 +2060,7 @@ var xxx_messageInfo_JWTTokens proto.InternalMessageInfo func (m *JsonnetVar) Reset() { *m = JsonnetVar{} } func (*JsonnetVar) ProtoMessage() {} func (*JsonnetVar) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{68} + return fileDescriptor_030104ce3b95bcac, []int{72} } func (m *JsonnetVar) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1973,7 +2088,7 @@ var xxx_messageInfo_JsonnetVar proto.InternalMessageInfo func (m *KnownTypeField) Reset() { *m = KnownTypeField{} } func (*KnownTypeField) ProtoMessage() {} func (*KnownTypeField) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{69} + return fileDescriptor_030104ce3b95bcac, []int{73} } func (m *KnownTypeField) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1998,10 +2113,38 @@ func (m *KnownTypeField) XXX_DiscardUnknown() { var xxx_messageInfo_KnownTypeField proto.InternalMessageInfo +func (m *KustomizeGvk) Reset() { *m = KustomizeGvk{} } +func (*KustomizeGvk) ProtoMessage() {} +func (*KustomizeGvk) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{74} +} +func (m *KustomizeGvk) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *KustomizeGvk) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *KustomizeGvk) XXX_Merge(src proto.Message) { + xxx_messageInfo_KustomizeGvk.Merge(m, src) +} +func (m *KustomizeGvk) XXX_Size() int { + return m.Size() +} +func (m *KustomizeGvk) XXX_DiscardUnknown() { + xxx_messageInfo_KustomizeGvk.DiscardUnknown(m) +} + +var xxx_messageInfo_KustomizeGvk proto.InternalMessageInfo + func (m *KustomizeOptions) Reset() { *m = KustomizeOptions{} } func (*KustomizeOptions) ProtoMessage() {} func (*KustomizeOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{70} + return fileDescriptor_030104ce3b95bcac, []int{75} } func (m *KustomizeOptions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2026,10 +2169,122 @@ func (m *KustomizeOptions) XXX_DiscardUnknown() { var xxx_messageInfo_KustomizeOptions proto.InternalMessageInfo +func (m *KustomizePatch) Reset() { *m = KustomizePatch{} } +func (*KustomizePatch) ProtoMessage() {} +func (*KustomizePatch) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{76} +} +func (m *KustomizePatch) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *KustomizePatch) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *KustomizePatch) XXX_Merge(src proto.Message) { + xxx_messageInfo_KustomizePatch.Merge(m, src) +} +func (m *KustomizePatch) XXX_Size() int { + return m.Size() +} +func (m *KustomizePatch) XXX_DiscardUnknown() { + xxx_messageInfo_KustomizePatch.DiscardUnknown(m) +} + +var xxx_messageInfo_KustomizePatch proto.InternalMessageInfo + +func (m *KustomizeReplica) Reset() { *m = KustomizeReplica{} } +func (*KustomizeReplica) ProtoMessage() {} +func (*KustomizeReplica) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{77} +} +func (m *KustomizeReplica) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *KustomizeReplica) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *KustomizeReplica) XXX_Merge(src proto.Message) { + xxx_messageInfo_KustomizeReplica.Merge(m, src) +} +func (m *KustomizeReplica) XXX_Size() int { + return m.Size() +} +func (m *KustomizeReplica) XXX_DiscardUnknown() { + xxx_messageInfo_KustomizeReplica.DiscardUnknown(m) +} + +var xxx_messageInfo_KustomizeReplica proto.InternalMessageInfo + +func (m *KustomizeResId) Reset() { *m = KustomizeResId{} } +func (*KustomizeResId) ProtoMessage() {} +func (*KustomizeResId) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{78} +} +func (m *KustomizeResId) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *KustomizeResId) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *KustomizeResId) XXX_Merge(src proto.Message) { + xxx_messageInfo_KustomizeResId.Merge(m, src) +} +func (m *KustomizeResId) XXX_Size() int { + return m.Size() +} +func (m *KustomizeResId) XXX_DiscardUnknown() { + xxx_messageInfo_KustomizeResId.DiscardUnknown(m) +} + +var xxx_messageInfo_KustomizeResId proto.InternalMessageInfo + +func (m *KustomizeSelector) Reset() { *m = KustomizeSelector{} } +func (*KustomizeSelector) ProtoMessage() {} +func (*KustomizeSelector) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{79} +} +func (m *KustomizeSelector) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *KustomizeSelector) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *KustomizeSelector) XXX_Merge(src proto.Message) { + xxx_messageInfo_KustomizeSelector.Merge(m, src) +} +func (m *KustomizeSelector) XXX_Size() int { + return m.Size() +} +func (m *KustomizeSelector) XXX_DiscardUnknown() { + xxx_messageInfo_KustomizeSelector.DiscardUnknown(m) +} + +var xxx_messageInfo_KustomizeSelector proto.InternalMessageInfo + func (m *ListGenerator) Reset() { *m = ListGenerator{} } func (*ListGenerator) ProtoMessage() {} func (*ListGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{71} + return fileDescriptor_030104ce3b95bcac, []int{80} } func (m *ListGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2057,7 +2312,7 @@ var xxx_messageInfo_ListGenerator proto.InternalMessageInfo func (m *ManagedNamespaceMetadata) Reset() { *m = ManagedNamespaceMetadata{} } func (*ManagedNamespaceMetadata) ProtoMessage() {} func (*ManagedNamespaceMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{72} + return fileDescriptor_030104ce3b95bcac, []int{81} } func (m *ManagedNamespaceMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2085,7 +2340,7 @@ var xxx_messageInfo_ManagedNamespaceMetadata proto.InternalMessageInfo func (m *MatrixGenerator) Reset() { *m = MatrixGenerator{} } func (*MatrixGenerator) ProtoMessage() {} func (*MatrixGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{73} + return fileDescriptor_030104ce3b95bcac, []int{82} } func (m *MatrixGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2113,7 +2368,7 @@ var xxx_messageInfo_MatrixGenerator proto.InternalMessageInfo func (m *MergeGenerator) Reset() { *m = MergeGenerator{} } func (*MergeGenerator) ProtoMessage() {} func (*MergeGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{74} + return fileDescriptor_030104ce3b95bcac, []int{83} } func (m *MergeGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2141,7 +2396,7 @@ var xxx_messageInfo_MergeGenerator proto.InternalMessageInfo func (m *NestedMatrixGenerator) Reset() { *m = NestedMatrixGenerator{} } func (*NestedMatrixGenerator) ProtoMessage() {} func (*NestedMatrixGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{75} + return fileDescriptor_030104ce3b95bcac, []int{84} } func (m *NestedMatrixGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2169,7 +2424,7 @@ var xxx_messageInfo_NestedMatrixGenerator proto.InternalMessageInfo func (m *NestedMergeGenerator) Reset() { *m = NestedMergeGenerator{} } func (*NestedMergeGenerator) ProtoMessage() {} func (*NestedMergeGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{76} + return fileDescriptor_030104ce3b95bcac, []int{85} } func (m *NestedMergeGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2197,7 +2452,7 @@ var xxx_messageInfo_NestedMergeGenerator proto.InternalMessageInfo func (m *Operation) Reset() { *m = Operation{} } func (*Operation) ProtoMessage() {} func (*Operation) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{77} + return fileDescriptor_030104ce3b95bcac, []int{86} } func (m *Operation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2225,7 +2480,7 @@ var xxx_messageInfo_Operation proto.InternalMessageInfo func (m *OperationInitiator) Reset() { *m = OperationInitiator{} } func (*OperationInitiator) ProtoMessage() {} func (*OperationInitiator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{78} + return fileDescriptor_030104ce3b95bcac, []int{87} } func (m *OperationInitiator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2253,7 +2508,7 @@ var xxx_messageInfo_OperationInitiator proto.InternalMessageInfo func (m *OperationState) Reset() { *m = OperationState{} } func (*OperationState) ProtoMessage() {} func (*OperationState) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{79} + return fileDescriptor_030104ce3b95bcac, []int{88} } func (m *OperationState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2278,10 +2533,66 @@ func (m *OperationState) XXX_DiscardUnknown() { var xxx_messageInfo_OperationState proto.InternalMessageInfo +func (m *OptionalArray) Reset() { *m = OptionalArray{} } +func (*OptionalArray) ProtoMessage() {} +func (*OptionalArray) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{89} +} +func (m *OptionalArray) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *OptionalArray) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *OptionalArray) XXX_Merge(src proto.Message) { + xxx_messageInfo_OptionalArray.Merge(m, src) +} +func (m *OptionalArray) XXX_Size() int { + return m.Size() +} +func (m *OptionalArray) XXX_DiscardUnknown() { + xxx_messageInfo_OptionalArray.DiscardUnknown(m) +} + +var xxx_messageInfo_OptionalArray proto.InternalMessageInfo + +func (m *OptionalMap) Reset() { *m = OptionalMap{} } +func (*OptionalMap) ProtoMessage() {} +func (*OptionalMap) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{90} +} +func (m *OptionalMap) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *OptionalMap) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *OptionalMap) XXX_Merge(src proto.Message) { + xxx_messageInfo_OptionalMap.Merge(m, src) +} +func (m *OptionalMap) XXX_Size() int { + return m.Size() +} +func (m *OptionalMap) XXX_DiscardUnknown() { + xxx_messageInfo_OptionalMap.DiscardUnknown(m) +} + +var xxx_messageInfo_OptionalMap proto.InternalMessageInfo + func (m *OrphanedResourceKey) Reset() { *m = OrphanedResourceKey{} } func (*OrphanedResourceKey) ProtoMessage() {} func (*OrphanedResourceKey) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{80} + return fileDescriptor_030104ce3b95bcac, []int{91} } func (m *OrphanedResourceKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2309,7 +2620,7 @@ var xxx_messageInfo_OrphanedResourceKey proto.InternalMessageInfo func (m *OrphanedResourcesMonitorSettings) Reset() { *m = OrphanedResourcesMonitorSettings{} } func (*OrphanedResourcesMonitorSettings) ProtoMessage() {} func (*OrphanedResourcesMonitorSettings) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{81} + return fileDescriptor_030104ce3b95bcac, []int{92} } func (m *OrphanedResourcesMonitorSettings) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2337,7 +2648,7 @@ var xxx_messageInfo_OrphanedResourcesMonitorSettings proto.InternalMessageInfo func (m *OverrideIgnoreDiff) Reset() { *m = OverrideIgnoreDiff{} } func (*OverrideIgnoreDiff) ProtoMessage() {} func (*OverrideIgnoreDiff) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{82} + return fileDescriptor_030104ce3b95bcac, []int{93} } func (m *OverrideIgnoreDiff) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2362,10 +2673,94 @@ func (m *OverrideIgnoreDiff) XXX_DiscardUnknown() { var xxx_messageInfo_OverrideIgnoreDiff proto.InternalMessageInfo +func (m *PluginConfigMapRef) Reset() { *m = PluginConfigMapRef{} } +func (*PluginConfigMapRef) ProtoMessage() {} +func (*PluginConfigMapRef) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{94} +} +func (m *PluginConfigMapRef) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PluginConfigMapRef) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *PluginConfigMapRef) XXX_Merge(src proto.Message) { + xxx_messageInfo_PluginConfigMapRef.Merge(m, src) +} +func (m *PluginConfigMapRef) XXX_Size() int { + return m.Size() +} +func (m *PluginConfigMapRef) XXX_DiscardUnknown() { + xxx_messageInfo_PluginConfigMapRef.DiscardUnknown(m) +} + +var xxx_messageInfo_PluginConfigMapRef proto.InternalMessageInfo + +func (m *PluginGenerator) Reset() { *m = PluginGenerator{} } +func (*PluginGenerator) ProtoMessage() {} +func (*PluginGenerator) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{95} +} +func (m *PluginGenerator) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PluginGenerator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *PluginGenerator) XXX_Merge(src proto.Message) { + xxx_messageInfo_PluginGenerator.Merge(m, src) +} +func (m *PluginGenerator) XXX_Size() int { + return m.Size() +} +func (m *PluginGenerator) XXX_DiscardUnknown() { + xxx_messageInfo_PluginGenerator.DiscardUnknown(m) +} + +var xxx_messageInfo_PluginGenerator proto.InternalMessageInfo + +func (m *PluginInput) Reset() { *m = PluginInput{} } +func (*PluginInput) ProtoMessage() {} +func (*PluginInput) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{96} +} +func (m *PluginInput) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PluginInput) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *PluginInput) XXX_Merge(src proto.Message) { + xxx_messageInfo_PluginInput.Merge(m, src) +} +func (m *PluginInput) XXX_Size() int { + return m.Size() +} +func (m *PluginInput) XXX_DiscardUnknown() { + xxx_messageInfo_PluginInput.DiscardUnknown(m) +} + +var xxx_messageInfo_PluginInput proto.InternalMessageInfo + func (m *ProjectRole) Reset() { *m = ProjectRole{} } func (*ProjectRole) ProtoMessage() {} func (*ProjectRole) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{83} + return fileDescriptor_030104ce3b95bcac, []int{97} } func (m *ProjectRole) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2393,7 +2788,7 @@ var xxx_messageInfo_ProjectRole proto.InternalMessageInfo func (m *PullRequestGenerator) Reset() { *m = PullRequestGenerator{} } func (*PullRequestGenerator) ProtoMessage() {} func (*PullRequestGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{84} + return fileDescriptor_030104ce3b95bcac, []int{98} } func (m *PullRequestGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2418,10 +2813,66 @@ func (m *PullRequestGenerator) XXX_DiscardUnknown() { var xxx_messageInfo_PullRequestGenerator proto.InternalMessageInfo +func (m *PullRequestGeneratorAzureDevOps) Reset() { *m = PullRequestGeneratorAzureDevOps{} } +func (*PullRequestGeneratorAzureDevOps) ProtoMessage() {} +func (*PullRequestGeneratorAzureDevOps) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{99} +} +func (m *PullRequestGeneratorAzureDevOps) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PullRequestGeneratorAzureDevOps) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *PullRequestGeneratorAzureDevOps) XXX_Merge(src proto.Message) { + xxx_messageInfo_PullRequestGeneratorAzureDevOps.Merge(m, src) +} +func (m *PullRequestGeneratorAzureDevOps) XXX_Size() int { + return m.Size() +} +func (m *PullRequestGeneratorAzureDevOps) XXX_DiscardUnknown() { + xxx_messageInfo_PullRequestGeneratorAzureDevOps.DiscardUnknown(m) +} + +var xxx_messageInfo_PullRequestGeneratorAzureDevOps proto.InternalMessageInfo + +func (m *PullRequestGeneratorBitbucket) Reset() { *m = PullRequestGeneratorBitbucket{} } +func (*PullRequestGeneratorBitbucket) ProtoMessage() {} +func (*PullRequestGeneratorBitbucket) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{100} +} +func (m *PullRequestGeneratorBitbucket) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PullRequestGeneratorBitbucket) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *PullRequestGeneratorBitbucket) XXX_Merge(src proto.Message) { + xxx_messageInfo_PullRequestGeneratorBitbucket.Merge(m, src) +} +func (m *PullRequestGeneratorBitbucket) XXX_Size() int { + return m.Size() +} +func (m *PullRequestGeneratorBitbucket) XXX_DiscardUnknown() { + xxx_messageInfo_PullRequestGeneratorBitbucket.DiscardUnknown(m) +} + +var xxx_messageInfo_PullRequestGeneratorBitbucket proto.InternalMessageInfo + func (m *PullRequestGeneratorBitbucketServer) Reset() { *m = PullRequestGeneratorBitbucketServer{} } func (*PullRequestGeneratorBitbucketServer) ProtoMessage() {} func (*PullRequestGeneratorBitbucketServer) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{85} + return fileDescriptor_030104ce3b95bcac, []int{101} } func (m *PullRequestGeneratorBitbucketServer) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2449,7 +2900,7 @@ var xxx_messageInfo_PullRequestGeneratorBitbucketServer proto.InternalMessageInf func (m *PullRequestGeneratorFilter) Reset() { *m = PullRequestGeneratorFilter{} } func (*PullRequestGeneratorFilter) ProtoMessage() {} func (*PullRequestGeneratorFilter) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{86} + return fileDescriptor_030104ce3b95bcac, []int{102} } func (m *PullRequestGeneratorFilter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2477,7 +2928,7 @@ var xxx_messageInfo_PullRequestGeneratorFilter proto.InternalMessageInfo func (m *PullRequestGeneratorGitLab) Reset() { *m = PullRequestGeneratorGitLab{} } func (*PullRequestGeneratorGitLab) ProtoMessage() {} func (*PullRequestGeneratorGitLab) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{87} + return fileDescriptor_030104ce3b95bcac, []int{103} } func (m *PullRequestGeneratorGitLab) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2505,7 +2956,7 @@ var xxx_messageInfo_PullRequestGeneratorGitLab proto.InternalMessageInfo func (m *PullRequestGeneratorGitea) Reset() { *m = PullRequestGeneratorGitea{} } func (*PullRequestGeneratorGitea) ProtoMessage() {} func (*PullRequestGeneratorGitea) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{88} + return fileDescriptor_030104ce3b95bcac, []int{104} } func (m *PullRequestGeneratorGitea) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2533,7 +2984,7 @@ var xxx_messageInfo_PullRequestGeneratorGitea proto.InternalMessageInfo func (m *PullRequestGeneratorGithub) Reset() { *m = PullRequestGeneratorGithub{} } func (*PullRequestGeneratorGithub) ProtoMessage() {} func (*PullRequestGeneratorGithub) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{89} + return fileDescriptor_030104ce3b95bcac, []int{105} } func (m *PullRequestGeneratorGithub) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2561,7 +3012,7 @@ var xxx_messageInfo_PullRequestGeneratorGithub proto.InternalMessageInfo func (m *RefTarget) Reset() { *m = RefTarget{} } func (*RefTarget) ProtoMessage() {} func (*RefTarget) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{90} + return fileDescriptor_030104ce3b95bcac, []int{106} } func (m *RefTarget) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2589,7 +3040,7 @@ var xxx_messageInfo_RefTarget proto.InternalMessageInfo func (m *RepoCreds) Reset() { *m = RepoCreds{} } func (*RepoCreds) ProtoMessage() {} func (*RepoCreds) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{91} + return fileDescriptor_030104ce3b95bcac, []int{107} } func (m *RepoCreds) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2617,7 +3068,7 @@ var xxx_messageInfo_RepoCreds proto.InternalMessageInfo func (m *RepoCredsList) Reset() { *m = RepoCredsList{} } func (*RepoCredsList) ProtoMessage() {} func (*RepoCredsList) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{92} + return fileDescriptor_030104ce3b95bcac, []int{108} } func (m *RepoCredsList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2645,7 +3096,7 @@ var xxx_messageInfo_RepoCredsList proto.InternalMessageInfo func (m *Repository) Reset() { *m = Repository{} } func (*Repository) ProtoMessage() {} func (*Repository) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{93} + return fileDescriptor_030104ce3b95bcac, []int{109} } func (m *Repository) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2673,7 +3124,7 @@ var xxx_messageInfo_Repository proto.InternalMessageInfo func (m *RepositoryCertificate) Reset() { *m = RepositoryCertificate{} } func (*RepositoryCertificate) ProtoMessage() {} func (*RepositoryCertificate) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{94} + return fileDescriptor_030104ce3b95bcac, []int{110} } func (m *RepositoryCertificate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2701,7 +3152,7 @@ var xxx_messageInfo_RepositoryCertificate proto.InternalMessageInfo func (m *RepositoryCertificateList) Reset() { *m = RepositoryCertificateList{} } func (*RepositoryCertificateList) ProtoMessage() {} func (*RepositoryCertificateList) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{95} + return fileDescriptor_030104ce3b95bcac, []int{111} } func (m *RepositoryCertificateList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2729,7 +3180,7 @@ var xxx_messageInfo_RepositoryCertificateList proto.InternalMessageInfo func (m *RepositoryList) Reset() { *m = RepositoryList{} } func (*RepositoryList) ProtoMessage() {} func (*RepositoryList) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{96} + return fileDescriptor_030104ce3b95bcac, []int{112} } func (m *RepositoryList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2757,7 +3208,7 @@ var xxx_messageInfo_RepositoryList proto.InternalMessageInfo func (m *ResourceAction) Reset() { *m = ResourceAction{} } func (*ResourceAction) ProtoMessage() {} func (*ResourceAction) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{97} + return fileDescriptor_030104ce3b95bcac, []int{113} } func (m *ResourceAction) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2785,7 +3236,7 @@ var xxx_messageInfo_ResourceAction proto.InternalMessageInfo func (m *ResourceActionDefinition) Reset() { *m = ResourceActionDefinition{} } func (*ResourceActionDefinition) ProtoMessage() {} func (*ResourceActionDefinition) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{98} + return fileDescriptor_030104ce3b95bcac, []int{114} } func (m *ResourceActionDefinition) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2813,7 +3264,7 @@ var xxx_messageInfo_ResourceActionDefinition proto.InternalMessageInfo func (m *ResourceActionParam) Reset() { *m = ResourceActionParam{} } func (*ResourceActionParam) ProtoMessage() {} func (*ResourceActionParam) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{99} + return fileDescriptor_030104ce3b95bcac, []int{115} } func (m *ResourceActionParam) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2841,7 +3292,7 @@ var xxx_messageInfo_ResourceActionParam proto.InternalMessageInfo func (m *ResourceActions) Reset() { *m = ResourceActions{} } func (*ResourceActions) ProtoMessage() {} func (*ResourceActions) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{100} + return fileDescriptor_030104ce3b95bcac, []int{116} } func (m *ResourceActions) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2869,7 +3320,7 @@ var xxx_messageInfo_ResourceActions proto.InternalMessageInfo func (m *ResourceDiff) Reset() { *m = ResourceDiff{} } func (*ResourceDiff) ProtoMessage() {} func (*ResourceDiff) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{101} + return fileDescriptor_030104ce3b95bcac, []int{117} } func (m *ResourceDiff) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2897,7 +3348,7 @@ var xxx_messageInfo_ResourceDiff proto.InternalMessageInfo func (m *ResourceIgnoreDifferences) Reset() { *m = ResourceIgnoreDifferences{} } func (*ResourceIgnoreDifferences) ProtoMessage() {} func (*ResourceIgnoreDifferences) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{102} + return fileDescriptor_030104ce3b95bcac, []int{118} } func (m *ResourceIgnoreDifferences) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2925,7 +3376,7 @@ var xxx_messageInfo_ResourceIgnoreDifferences proto.InternalMessageInfo func (m *ResourceNetworkingInfo) Reset() { *m = ResourceNetworkingInfo{} } func (*ResourceNetworkingInfo) ProtoMessage() {} func (*ResourceNetworkingInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{103} + return fileDescriptor_030104ce3b95bcac, []int{119} } func (m *ResourceNetworkingInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2953,7 +3404,7 @@ var xxx_messageInfo_ResourceNetworkingInfo proto.InternalMessageInfo func (m *ResourceNode) Reset() { *m = ResourceNode{} } func (*ResourceNode) ProtoMessage() {} func (*ResourceNode) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{104} + return fileDescriptor_030104ce3b95bcac, []int{120} } func (m *ResourceNode) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2981,7 +3432,7 @@ var xxx_messageInfo_ResourceNode proto.InternalMessageInfo func (m *ResourceOverride) Reset() { *m = ResourceOverride{} } func (*ResourceOverride) ProtoMessage() {} func (*ResourceOverride) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{105} + return fileDescriptor_030104ce3b95bcac, []int{121} } func (m *ResourceOverride) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3009,7 +3460,7 @@ var xxx_messageInfo_ResourceOverride proto.InternalMessageInfo func (m *ResourceRef) Reset() { *m = ResourceRef{} } func (*ResourceRef) ProtoMessage() {} func (*ResourceRef) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{106} + return fileDescriptor_030104ce3b95bcac, []int{122} } func (m *ResourceRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3037,7 +3488,7 @@ var xxx_messageInfo_ResourceRef proto.InternalMessageInfo func (m *ResourceResult) Reset() { *m = ResourceResult{} } func (*ResourceResult) ProtoMessage() {} func (*ResourceResult) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{107} + return fileDescriptor_030104ce3b95bcac, []int{123} } func (m *ResourceResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3065,7 +3516,7 @@ var xxx_messageInfo_ResourceResult proto.InternalMessageInfo func (m *ResourceStatus) Reset() { *m = ResourceStatus{} } func (*ResourceStatus) ProtoMessage() {} func (*ResourceStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{108} + return fileDescriptor_030104ce3b95bcac, []int{124} } func (m *ResourceStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3093,7 +3544,7 @@ var xxx_messageInfo_ResourceStatus proto.InternalMessageInfo func (m *RetryStrategy) Reset() { *m = RetryStrategy{} } func (*RetryStrategy) ProtoMessage() {} func (*RetryStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{109} + return fileDescriptor_030104ce3b95bcac, []int{125} } func (m *RetryStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3121,7 +3572,7 @@ var xxx_messageInfo_RetryStrategy proto.InternalMessageInfo func (m *RevisionHistory) Reset() { *m = RevisionHistory{} } func (*RevisionHistory) ProtoMessage() {} func (*RevisionHistory) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{110} + return fileDescriptor_030104ce3b95bcac, []int{126} } func (m *RevisionHistory) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3149,7 +3600,7 @@ var xxx_messageInfo_RevisionHistory proto.InternalMessageInfo func (m *RevisionMetadata) Reset() { *m = RevisionMetadata{} } func (*RevisionMetadata) ProtoMessage() {} func (*RevisionMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{111} + return fileDescriptor_030104ce3b95bcac, []int{127} } func (m *RevisionMetadata) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3177,7 +3628,7 @@ var xxx_messageInfo_RevisionMetadata proto.InternalMessageInfo func (m *SCMProviderGenerator) Reset() { *m = SCMProviderGenerator{} } func (*SCMProviderGenerator) ProtoMessage() {} func (*SCMProviderGenerator) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{112} + return fileDescriptor_030104ce3b95bcac, []int{128} } func (m *SCMProviderGenerator) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3202,10 +3653,38 @@ func (m *SCMProviderGenerator) XXX_DiscardUnknown() { var xxx_messageInfo_SCMProviderGenerator proto.InternalMessageInfo +func (m *SCMProviderGeneratorAWSCodeCommit) Reset() { *m = SCMProviderGeneratorAWSCodeCommit{} } +func (*SCMProviderGeneratorAWSCodeCommit) ProtoMessage() {} +func (*SCMProviderGeneratorAWSCodeCommit) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{129} +} +func (m *SCMProviderGeneratorAWSCodeCommit) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SCMProviderGeneratorAWSCodeCommit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *SCMProviderGeneratorAWSCodeCommit) XXX_Merge(src proto.Message) { + xxx_messageInfo_SCMProviderGeneratorAWSCodeCommit.Merge(m, src) +} +func (m *SCMProviderGeneratorAWSCodeCommit) XXX_Size() int { + return m.Size() +} +func (m *SCMProviderGeneratorAWSCodeCommit) XXX_DiscardUnknown() { + xxx_messageInfo_SCMProviderGeneratorAWSCodeCommit.DiscardUnknown(m) +} + +var xxx_messageInfo_SCMProviderGeneratorAWSCodeCommit proto.InternalMessageInfo + func (m *SCMProviderGeneratorAzureDevOps) Reset() { *m = SCMProviderGeneratorAzureDevOps{} } func (*SCMProviderGeneratorAzureDevOps) ProtoMessage() {} func (*SCMProviderGeneratorAzureDevOps) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{113} + return fileDescriptor_030104ce3b95bcac, []int{130} } func (m *SCMProviderGeneratorAzureDevOps) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3233,7 +3712,7 @@ var xxx_messageInfo_SCMProviderGeneratorAzureDevOps proto.InternalMessageInfo func (m *SCMProviderGeneratorBitbucket) Reset() { *m = SCMProviderGeneratorBitbucket{} } func (*SCMProviderGeneratorBitbucket) ProtoMessage() {} func (*SCMProviderGeneratorBitbucket) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{114} + return fileDescriptor_030104ce3b95bcac, []int{131} } func (m *SCMProviderGeneratorBitbucket) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3261,7 +3740,7 @@ var xxx_messageInfo_SCMProviderGeneratorBitbucket proto.InternalMessageInfo func (m *SCMProviderGeneratorBitbucketServer) Reset() { *m = SCMProviderGeneratorBitbucketServer{} } func (*SCMProviderGeneratorBitbucketServer) ProtoMessage() {} func (*SCMProviderGeneratorBitbucketServer) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{115} + return fileDescriptor_030104ce3b95bcac, []int{132} } func (m *SCMProviderGeneratorBitbucketServer) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3289,7 +3768,7 @@ var xxx_messageInfo_SCMProviderGeneratorBitbucketServer proto.InternalMessageInf func (m *SCMProviderGeneratorFilter) Reset() { *m = SCMProviderGeneratorFilter{} } func (*SCMProviderGeneratorFilter) ProtoMessage() {} func (*SCMProviderGeneratorFilter) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{116} + return fileDescriptor_030104ce3b95bcac, []int{133} } func (m *SCMProviderGeneratorFilter) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3317,7 +3796,7 @@ var xxx_messageInfo_SCMProviderGeneratorFilter proto.InternalMessageInfo func (m *SCMProviderGeneratorGitea) Reset() { *m = SCMProviderGeneratorGitea{} } func (*SCMProviderGeneratorGitea) ProtoMessage() {} func (*SCMProviderGeneratorGitea) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{117} + return fileDescriptor_030104ce3b95bcac, []int{134} } func (m *SCMProviderGeneratorGitea) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3345,7 +3824,7 @@ var xxx_messageInfo_SCMProviderGeneratorGitea proto.InternalMessageInfo func (m *SCMProviderGeneratorGithub) Reset() { *m = SCMProviderGeneratorGithub{} } func (*SCMProviderGeneratorGithub) ProtoMessage() {} func (*SCMProviderGeneratorGithub) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{118} + return fileDescriptor_030104ce3b95bcac, []int{135} } func (m *SCMProviderGeneratorGithub) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3373,7 +3852,7 @@ var xxx_messageInfo_SCMProviderGeneratorGithub proto.InternalMessageInfo func (m *SCMProviderGeneratorGitlab) Reset() { *m = SCMProviderGeneratorGitlab{} } func (*SCMProviderGeneratorGitlab) ProtoMessage() {} func (*SCMProviderGeneratorGitlab) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{119} + return fileDescriptor_030104ce3b95bcac, []int{136} } func (m *SCMProviderGeneratorGitlab) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3401,7 +3880,7 @@ var xxx_messageInfo_SCMProviderGeneratorGitlab proto.InternalMessageInfo func (m *SecretRef) Reset() { *m = SecretRef{} } func (*SecretRef) ProtoMessage() {} func (*SecretRef) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{120} + return fileDescriptor_030104ce3b95bcac, []int{137} } func (m *SecretRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3429,7 +3908,7 @@ var xxx_messageInfo_SecretRef proto.InternalMessageInfo func (m *SignatureKey) Reset() { *m = SignatureKey{} } func (*SignatureKey) ProtoMessage() {} func (*SignatureKey) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{121} + return fileDescriptor_030104ce3b95bcac, []int{138} } func (m *SignatureKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3457,7 +3936,7 @@ var xxx_messageInfo_SignatureKey proto.InternalMessageInfo func (m *SyncOperation) Reset() { *m = SyncOperation{} } func (*SyncOperation) ProtoMessage() {} func (*SyncOperation) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{122} + return fileDescriptor_030104ce3b95bcac, []int{139} } func (m *SyncOperation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3485,7 +3964,7 @@ var xxx_messageInfo_SyncOperation proto.InternalMessageInfo func (m *SyncOperationResource) Reset() { *m = SyncOperationResource{} } func (*SyncOperationResource) ProtoMessage() {} func (*SyncOperationResource) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{123} + return fileDescriptor_030104ce3b95bcac, []int{140} } func (m *SyncOperationResource) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3513,7 +3992,7 @@ var xxx_messageInfo_SyncOperationResource proto.InternalMessageInfo func (m *SyncOperationResult) Reset() { *m = SyncOperationResult{} } func (*SyncOperationResult) ProtoMessage() {} func (*SyncOperationResult) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{124} + return fileDescriptor_030104ce3b95bcac, []int{141} } func (m *SyncOperationResult) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3541,7 +4020,7 @@ var xxx_messageInfo_SyncOperationResult proto.InternalMessageInfo func (m *SyncPolicy) Reset() { *m = SyncPolicy{} } func (*SyncPolicy) ProtoMessage() {} func (*SyncPolicy) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{125} + return fileDescriptor_030104ce3b95bcac, []int{142} } func (m *SyncPolicy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3569,7 +4048,7 @@ var xxx_messageInfo_SyncPolicy proto.InternalMessageInfo func (m *SyncPolicyAutomated) Reset() { *m = SyncPolicyAutomated{} } func (*SyncPolicyAutomated) ProtoMessage() {} func (*SyncPolicyAutomated) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{126} + return fileDescriptor_030104ce3b95bcac, []int{143} } func (m *SyncPolicyAutomated) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3597,7 +4076,7 @@ var xxx_messageInfo_SyncPolicyAutomated proto.InternalMessageInfo func (m *SyncStatus) Reset() { *m = SyncStatus{} } func (*SyncStatus) ProtoMessage() {} func (*SyncStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{127} + return fileDescriptor_030104ce3b95bcac, []int{144} } func (m *SyncStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3625,7 +4104,7 @@ var xxx_messageInfo_SyncStatus proto.InternalMessageInfo func (m *SyncStrategy) Reset() { *m = SyncStrategy{} } func (*SyncStrategy) ProtoMessage() {} func (*SyncStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{128} + return fileDescriptor_030104ce3b95bcac, []int{145} } func (m *SyncStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3653,7 +4132,7 @@ var xxx_messageInfo_SyncStrategy proto.InternalMessageInfo func (m *SyncStrategyApply) Reset() { *m = SyncStrategyApply{} } func (*SyncStrategyApply) ProtoMessage() {} func (*SyncStrategyApply) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{129} + return fileDescriptor_030104ce3b95bcac, []int{146} } func (m *SyncStrategyApply) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3681,7 +4160,7 @@ var xxx_messageInfo_SyncStrategyApply proto.InternalMessageInfo func (m *SyncStrategyHook) Reset() { *m = SyncStrategyHook{} } func (*SyncStrategyHook) ProtoMessage() {} func (*SyncStrategyHook) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{130} + return fileDescriptor_030104ce3b95bcac, []int{147} } func (m *SyncStrategyHook) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3709,7 +4188,7 @@ var xxx_messageInfo_SyncStrategyHook proto.InternalMessageInfo func (m *SyncWindow) Reset() { *m = SyncWindow{} } func (*SyncWindow) ProtoMessage() {} func (*SyncWindow) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{131} + return fileDescriptor_030104ce3b95bcac, []int{148} } func (m *SyncWindow) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3737,7 +4216,7 @@ var xxx_messageInfo_SyncWindow proto.InternalMessageInfo func (m *TLSClientConfig) Reset() { *m = TLSClientConfig{} } func (*TLSClientConfig) ProtoMessage() {} func (*TLSClientConfig) Descriptor() ([]byte, []int) { - return fileDescriptor_030104ce3b95bcac, []int{132} + return fileDescriptor_030104ce3b95bcac, []int{149} } func (m *TLSClientConfig) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3762,6 +4241,34 @@ func (m *TLSClientConfig) XXX_DiscardUnknown() { var xxx_messageInfo_TLSClientConfig proto.InternalMessageInfo +func (m *TagFilter) Reset() { *m = TagFilter{} } +func (*TagFilter) ProtoMessage() {} +func (*TagFilter) Descriptor() ([]byte, []int) { + return fileDescriptor_030104ce3b95bcac, []int{150} +} +func (m *TagFilter) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TagFilter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *TagFilter) XXX_Merge(src proto.Message) { + xxx_messageInfo_TagFilter.Merge(m, src) +} +func (m *TagFilter) XXX_Size() int { + return m.Size() +} +func (m *TagFilter) XXX_DiscardUnknown() { + xxx_messageInfo_TagFilter.DiscardUnknown(m) +} + +var xxx_messageInfo_TagFilter proto.InternalMessageInfo + func init() { proto.RegisterType((*AWSAuthConfig)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.AWSAuthConfig") proto.RegisterType((*AppProject)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.AppProject") @@ -3774,12 +4281,14 @@ func init() { proto.RegisterType((*ApplicationDestination)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationDestination") proto.RegisterType((*ApplicationList)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationList") proto.RegisterType((*ApplicationMatchExpression)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationMatchExpression") + proto.RegisterType((*ApplicationPreservedFields)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationPreservedFields") proto.RegisterType((*ApplicationSet)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSet") proto.RegisterType((*ApplicationSetApplicationStatus)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSetApplicationStatus") proto.RegisterType((*ApplicationSetCondition)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSetCondition") proto.RegisterType((*ApplicationSetGenerator)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSetGenerator") proto.RegisterType((*ApplicationSetList)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSetList") proto.RegisterType((*ApplicationSetNestedGenerator)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSetNestedGenerator") + proto.RegisterType((*ApplicationSetResourceIgnoreDifferences)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSetResourceIgnoreDifferences") proto.RegisterType((*ApplicationSetRolloutStep)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSetRolloutStep") proto.RegisterType((*ApplicationSetRolloutStrategy)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSetRolloutStrategy") proto.RegisterType((*ApplicationSetSpec)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSetSpec") @@ -3800,7 +4309,6 @@ func init() { proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSourceKustomize.CommonLabelsEntry") proto.RegisterType((*ApplicationSourcePlugin)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSourcePlugin") proto.RegisterType((*ApplicationSourcePluginParameter)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSourcePluginParameter") - proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSourcePluginParameter.MapEntry") proto.RegisterType((*ApplicationSpec)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSpec") proto.RegisterType((*ApplicationStatus)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationStatus") proto.RegisterType((*ApplicationSummary)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSummary") @@ -3808,6 +4316,8 @@ func init() { proto.RegisterType((*ApplicationWatchEvent)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationWatchEvent") proto.RegisterType((*Backoff)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Backoff") proto.RegisterType((*BasicAuthBitbucketServer)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.BasicAuthBitbucketServer") + proto.RegisterType((*BearerTokenBitbucketCloud)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.BearerTokenBitbucketCloud") + proto.RegisterType((*ChartDetails)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ChartDetails") proto.RegisterType((*Cluster)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Cluster") proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Cluster.AnnotationsEntry") proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Cluster.LabelsEntry") @@ -3830,6 +4340,7 @@ func init() { proto.RegisterType((*GitDirectoryGeneratorItem)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.GitDirectoryGeneratorItem") proto.RegisterType((*GitFileGeneratorItem)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.GitFileGeneratorItem") proto.RegisterType((*GitGenerator)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.GitGenerator") + proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.GitGenerator.ValuesEntry") proto.RegisterType((*GnuPGPublicKey)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.GnuPGPublicKey") proto.RegisterType((*GnuPGPublicKeyList)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.GnuPGPublicKeyList") proto.RegisterType((*HealthStatus)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.HealthStatus") @@ -3844,7 +4355,13 @@ func init() { proto.RegisterType((*JWTTokens)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.JWTTokens") proto.RegisterType((*JsonnetVar)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.JsonnetVar") proto.RegisterType((*KnownTypeField)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.KnownTypeField") + proto.RegisterType((*KustomizeGvk)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.KustomizeGvk") proto.RegisterType((*KustomizeOptions)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.KustomizeOptions") + proto.RegisterType((*KustomizePatch)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.KustomizePatch") + proto.RegisterMapType((map[string]bool)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.KustomizePatch.OptionsEntry") + proto.RegisterType((*KustomizeReplica)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.KustomizeReplica") + proto.RegisterType((*KustomizeResId)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.KustomizeResId") + proto.RegisterType((*KustomizeSelector)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.KustomizeSelector") proto.RegisterType((*ListGenerator)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ListGenerator") proto.RegisterType((*ManagedNamespaceMetadata)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ManagedNamespaceMetadata") proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ManagedNamespaceMetadata.AnnotationsEntry") @@ -3856,11 +4373,21 @@ func init() { proto.RegisterType((*Operation)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Operation") proto.RegisterType((*OperationInitiator)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.OperationInitiator") proto.RegisterType((*OperationState)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.OperationState") + proto.RegisterType((*OptionalArray)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.OptionalArray") + proto.RegisterType((*OptionalMap)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.OptionalMap") + proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.OptionalMap.MapEntry") proto.RegisterType((*OrphanedResourceKey)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.OrphanedResourceKey") proto.RegisterType((*OrphanedResourcesMonitorSettings)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.OrphanedResourcesMonitorSettings") proto.RegisterType((*OverrideIgnoreDiff)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.OverrideIgnoreDiff") + proto.RegisterType((*PluginConfigMapRef)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.PluginConfigMapRef") + proto.RegisterType((*PluginGenerator)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.PluginGenerator") + proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.PluginGenerator.ValuesEntry") + proto.RegisterType((*PluginInput)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.PluginInput") + proto.RegisterMapType((PluginParameters)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.PluginInput.ParametersEntry") proto.RegisterType((*ProjectRole)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ProjectRole") proto.RegisterType((*PullRequestGenerator)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.PullRequestGenerator") + proto.RegisterType((*PullRequestGeneratorAzureDevOps)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.PullRequestGeneratorAzureDevOps") + proto.RegisterType((*PullRequestGeneratorBitbucket)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.PullRequestGeneratorBitbucket") proto.RegisterType((*PullRequestGeneratorBitbucketServer)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.PullRequestGeneratorBitbucketServer") proto.RegisterType((*PullRequestGeneratorFilter)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.PullRequestGeneratorFilter") proto.RegisterType((*PullRequestGeneratorGitLab)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.PullRequestGeneratorGitLab") @@ -3891,6 +4418,8 @@ func init() { proto.RegisterType((*RevisionHistory)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.RevisionHistory") proto.RegisterType((*RevisionMetadata)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.RevisionMetadata") proto.RegisterType((*SCMProviderGenerator)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.SCMProviderGenerator") + proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.SCMProviderGenerator.ValuesEntry") + proto.RegisterType((*SCMProviderGeneratorAWSCodeCommit)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.SCMProviderGeneratorAWSCodeCommit") proto.RegisterType((*SCMProviderGeneratorAzureDevOps)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.SCMProviderGeneratorAzureDevOps") proto.RegisterType((*SCMProviderGeneratorBitbucket)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.SCMProviderGeneratorBitbucket") proto.RegisterType((*SCMProviderGeneratorBitbucketServer)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.SCMProviderGeneratorBitbucketServer") @@ -3911,6 +4440,7 @@ func init() { proto.RegisterType((*SyncStrategyHook)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.SyncStrategyHook") proto.RegisterType((*SyncWindow)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.SyncWindow") proto.RegisterType((*TLSClientConfig)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.TLSClientConfig") + proto.RegisterType((*TagFilter)(nil), "github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.TagFilter") } func init() { @@ -3918,609 +4448,697 @@ func init() { } var fileDescriptor_030104ce3b95bcac = []byte{ - // 9618 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xbd, 0x6f, 0x70, 0x24, 0xc7, - 0x75, 0x18, 0xae, 0xd9, 0xc5, 0x02, 0xbb, 0x0f, 0x7f, 0xee, 0xd0, 0x77, 0x47, 0x82, 0x47, 0xf2, - 0x70, 0x35, 0x2c, 0x53, 0xd4, 0x4f, 0x24, 0xf0, 0xe3, 0x89, 0x52, 0x18, 0xd3, 0xa6, 0x8c, 0x05, - 0xee, 0x70, 0xb8, 0x03, 0x0e, 0x60, 0x03, 0x77, 0x27, 0x91, 0xa6, 0xa4, 0xc1, 0x6c, 0xef, 0x62, - 0x0e, 0xb3, 0x33, 0xcb, 0x99, 0x59, 0x1c, 0x96, 0x96, 0x65, 0x49, 0x96, 0x6d, 0x25, 0xfa, 0x43, - 0x85, 0xfe, 0x10, 0xb9, 0x92, 0xd8, 0x8a, 0xed, 0x72, 0xc5, 0x95, 0xa8, 0xe2, 0x54, 0x3e, 0x24, - 0x4e, 0x2a, 0x55, 0x89, 0x9d, 0x0f, 0x4c, 0x29, 0x55, 0x51, 0x55, 0x5c, 0x96, 0x13, 0x3b, 0x30, - 0x75, 0xa9, 0x54, 0x52, 0xa9, 0x8a, 0x53, 0xf9, 0xf3, 0x25, 0x57, 0xf9, 0x90, 0xea, 0xff, 0x3d, - 0xb3, 0xbb, 0x87, 0xdd, 0xc3, 0xe0, 0xee, 0xa4, 0xe2, 0xb7, 0xdd, 0x7e, 0x6f, 0xde, 0xeb, 0xe9, - 0xe9, 0x7e, 0xfd, 0x5e, 0xbf, 0x3f, 0x0d, 0xab, 0x0d, 0x2f, 0xd9, 0x69, 0x6f, 0xcf, 0xb9, 0x61, - 0x73, 0xde, 0x89, 0x1a, 0x61, 0x2b, 0x0a, 0x6f, 0xb1, 0x1f, 0x2f, 0xb8, 0xb5, 0xf9, 0xbd, 0x0b, - 0xf3, 0xad, 0xdd, 0xc6, 0xbc, 0xd3, 0xf2, 0xe2, 0x79, 0xa7, 0xd5, 0xf2, 0x3d, 0xd7, 0x49, 0xbc, - 0x30, 0x98, 0xdf, 0x7b, 0xd1, 0xf1, 0x5b, 0x3b, 0xce, 0x8b, 0xf3, 0x0d, 0x12, 0x90, 0xc8, 0x49, - 0x48, 0x6d, 0xae, 0x15, 0x85, 0x49, 0x88, 0x7e, 0x4a, 0x53, 0x9b, 0x93, 0xd4, 0xd8, 0x8f, 0xcf, - 0xba, 0xb5, 0xb9, 0xbd, 0x0b, 0x73, 0xad, 0xdd, 0xc6, 0x1c, 0xa5, 0x36, 0x67, 0x50, 0x9b, 0x93, - 0xd4, 0xce, 0xbe, 0x60, 0xf4, 0xa5, 0x11, 0x36, 0xc2, 0x79, 0x46, 0x74, 0xbb, 0x5d, 0x67, 0xff, - 0xd8, 0x1f, 0xf6, 0x8b, 0x33, 0x3b, 0x6b, 0xef, 0xbe, 0x1c, 0xcf, 0x79, 0x21, 0xed, 0xde, 0xbc, - 0x1b, 0x46, 0x64, 0x7e, 0xaf, 0xab, 0x43, 0x67, 0x2f, 0x6b, 0x1c, 0xb2, 0x9f, 0x90, 0x20, 0xf6, - 0xc2, 0x20, 0x7e, 0x81, 0x76, 0x81, 0x44, 0x7b, 0x24, 0x32, 0x5f, 0xcf, 0x40, 0xe8, 0x45, 0xe9, - 0x25, 0x4d, 0xa9, 0xe9, 0xb8, 0x3b, 0x5e, 0x40, 0xa2, 0x8e, 0x7e, 0xbc, 0x49, 0x12, 0xa7, 0xd7, - 0x53, 0xf3, 0xfd, 0x9e, 0x8a, 0xda, 0x41, 0xe2, 0x35, 0x49, 0xd7, 0x03, 0x9f, 0x38, 0xec, 0x81, - 0xd8, 0xdd, 0x21, 0x4d, 0xa7, 0xeb, 0xb9, 0x8f, 0xf5, 0x7b, 0xae, 0x9d, 0x78, 0xfe, 0xbc, 0x17, - 0x24, 0x71, 0x12, 0x65, 0x1f, 0xb2, 0xdf, 0x82, 0xc9, 0x85, 0x9b, 0x9b, 0x0b, 0xed, 0x64, 0x67, - 0x31, 0x0c, 0xea, 0x5e, 0x03, 0x7d, 0x1c, 0xc6, 0x5d, 0xbf, 0x1d, 0x27, 0x24, 0xba, 0xe6, 0x34, - 0xc9, 0x8c, 0x75, 0xde, 0x7a, 0xae, 0x52, 0x3d, 0xf5, 0xde, 0xc1, 0xec, 0x87, 0xee, 0x1c, 0xcc, - 0x8e, 0x2f, 0x6a, 0x10, 0x36, 0xf1, 0xd0, 0x47, 0x60, 0x2c, 0x0a, 0x7d, 0xb2, 0x80, 0xaf, 0xcd, - 0x14, 0xd8, 0x23, 0x27, 0xc4, 0x23, 0x63, 0x98, 0x37, 0x63, 0x09, 0xb7, 0xff, 0xb8, 0x00, 0xb0, - 0xd0, 0x6a, 0x6d, 0x44, 0xe1, 0x2d, 0xe2, 0x26, 0xe8, 0x73, 0x50, 0xa6, 0x43, 0x57, 0x73, 0x12, - 0x87, 0x71, 0x1b, 0xbf, 0xf0, 0xff, 0xcf, 0xf1, 0x37, 0x99, 0x33, 0xdf, 0x44, 0x4f, 0x1c, 0x8a, - 0x3d, 0xb7, 0xf7, 0xe2, 0xdc, 0xfa, 0x36, 0x7d, 0x7e, 0x8d, 0x24, 0x4e, 0x15, 0x09, 0x66, 0xa0, - 0xdb, 0xb0, 0xa2, 0x8a, 0x02, 0x18, 0x89, 0x5b, 0xc4, 0x65, 0x1d, 0x1b, 0xbf, 0xb0, 0x3a, 0x77, - 0x94, 0x19, 0x3a, 0xa7, 0x7b, 0xbe, 0xd9, 0x22, 0x6e, 0x75, 0x42, 0x70, 0x1e, 0xa1, 0xff, 0x30, - 0xe3, 0x83, 0xf6, 0x60, 0x34, 0x4e, 0x9c, 0xa4, 0x1d, 0xcf, 0x14, 0x19, 0xc7, 0x6b, 0xb9, 0x71, - 0x64, 0x54, 0xab, 0x53, 0x82, 0xe7, 0x28, 0xff, 0x8f, 0x05, 0x37, 0xfb, 0x3f, 0x58, 0x30, 0xa5, - 0x91, 0x57, 0xbd, 0x38, 0x41, 0x3f, 0xdb, 0x35, 0xb8, 0x73, 0x83, 0x0d, 0x2e, 0x7d, 0x9a, 0x0d, - 0xed, 0x49, 0xc1, 0xac, 0x2c, 0x5b, 0x8c, 0x81, 0x6d, 0x42, 0xc9, 0x4b, 0x48, 0x33, 0x9e, 0x29, - 0x9c, 0x2f, 0x3e, 0x37, 0x7e, 0xe1, 0x72, 0x5e, 0xef, 0x59, 0x9d, 0x14, 0x4c, 0x4b, 0x2b, 0x94, - 0x3c, 0xe6, 0x5c, 0xec, 0xdf, 0x9d, 0x30, 0xdf, 0x8f, 0x0e, 0x38, 0x7a, 0x11, 0xc6, 0xe3, 0xb0, - 0x1d, 0xb9, 0x04, 0x93, 0x56, 0x18, 0xcf, 0x58, 0xe7, 0x8b, 0x74, 0xea, 0xd1, 0x99, 0xba, 0xa9, - 0x9b, 0xb1, 0x89, 0x83, 0xbe, 0x69, 0xc1, 0x44, 0x8d, 0xc4, 0x89, 0x17, 0x30, 0xfe, 0xb2, 0xf3, - 0x5b, 0x47, 0xee, 0xbc, 0x6c, 0x5c, 0xd2, 0xc4, 0xab, 0xa7, 0xc5, 0x8b, 0x4c, 0x18, 0x8d, 0x31, - 0x4e, 0xf1, 0xa7, 0x2b, 0xae, 0x46, 0x62, 0x37, 0xf2, 0x5a, 0xf4, 0x3f, 0x9b, 0x33, 0xc6, 0x8a, - 0x5b, 0xd2, 0x20, 0x6c, 0xe2, 0xa1, 0x00, 0x4a, 0x74, 0x45, 0xc5, 0x33, 0x23, 0xac, 0xff, 0x2b, - 0x47, 0xeb, 0xbf, 0x18, 0x54, 0xba, 0x58, 0xf5, 0xe8, 0xd3, 0x7f, 0x31, 0xe6, 0x6c, 0xd0, 0x37, - 0x2c, 0x98, 0x11, 0x2b, 0x1e, 0x13, 0x3e, 0xa0, 0x37, 0x77, 0xbc, 0x84, 0xf8, 0x5e, 0x9c, 0xcc, - 0x94, 0x58, 0x1f, 0xe6, 0x07, 0x9b, 0x5b, 0xcb, 0x51, 0xd8, 0x6e, 0x5d, 0xf5, 0x82, 0x5a, 0xf5, - 0xbc, 0xe0, 0x34, 0xb3, 0xd8, 0x87, 0x30, 0xee, 0xcb, 0x12, 0xfd, 0xaa, 0x05, 0x67, 0x03, 0xa7, - 0x49, 0xe2, 0x96, 0x43, 0x3f, 0x2d, 0x07, 0x57, 0x7d, 0xc7, 0xdd, 0x65, 0x3d, 0x1a, 0xbd, 0xbf, - 0x1e, 0xd9, 0xa2, 0x47, 0x67, 0xaf, 0xf5, 0x25, 0x8d, 0xef, 0xc1, 0x16, 0xfd, 0x96, 0x05, 0xd3, - 0x61, 0xd4, 0xda, 0x71, 0x02, 0x52, 0x93, 0xd0, 0x78, 0x66, 0x8c, 0x2d, 0xbd, 0xcf, 0x1c, 0xed, - 0x13, 0xad, 0x67, 0xc9, 0xae, 0x85, 0x81, 0x97, 0x84, 0xd1, 0x26, 0x49, 0x12, 0x2f, 0x68, 0xc4, - 0xd5, 0x33, 0x77, 0x0e, 0x66, 0xa7, 0xbb, 0xb0, 0x70, 0x77, 0x7f, 0xd0, 0xcf, 0xc1, 0x78, 0xdc, - 0x09, 0xdc, 0x9b, 0x5e, 0x50, 0x0b, 0x6f, 0xc7, 0x33, 0xe5, 0x3c, 0x96, 0xef, 0xa6, 0x22, 0x28, - 0x16, 0xa0, 0x66, 0x80, 0x4d, 0x6e, 0xbd, 0x3f, 0x9c, 0x9e, 0x4a, 0x95, 0xbc, 0x3f, 0x9c, 0x9e, - 0x4c, 0xf7, 0x60, 0x8b, 0x7e, 0xc5, 0x82, 0xc9, 0xd8, 0x6b, 0x04, 0x4e, 0xd2, 0x8e, 0xc8, 0x55, - 0xd2, 0x89, 0x67, 0x80, 0x75, 0xe4, 0xca, 0x11, 0x47, 0xc5, 0x20, 0x59, 0x3d, 0x23, 0xfa, 0x38, - 0x69, 0xb6, 0xc6, 0x38, 0xcd, 0xb7, 0xd7, 0x42, 0xd3, 0xd3, 0x7a, 0x3c, 0xdf, 0x85, 0xa6, 0x27, - 0x75, 0x5f, 0x96, 0xe8, 0x67, 0xe0, 0x24, 0x6f, 0x52, 0x23, 0x1b, 0xcf, 0x4c, 0x30, 0x41, 0x7b, - 0xfa, 0xce, 0xc1, 0xec, 0xc9, 0xcd, 0x0c, 0x0c, 0x77, 0x61, 0xa3, 0xb7, 0x60, 0xb6, 0x45, 0xa2, - 0xa6, 0x97, 0xac, 0x07, 0x7e, 0x47, 0x8a, 0x6f, 0x37, 0x6c, 0x91, 0x9a, 0xe8, 0x4e, 0x3c, 0x33, - 0x79, 0xde, 0x7a, 0xae, 0x5c, 0xfd, 0xb0, 0xe8, 0xe6, 0xec, 0xc6, 0xbd, 0xd1, 0xf1, 0x61, 0xf4, - 0xec, 0x7f, 0x55, 0x80, 0x93, 0xd9, 0x8d, 0x13, 0xfd, 0x8e, 0x05, 0x27, 0x6e, 0xdd, 0x4e, 0xb6, - 0xc2, 0x5d, 0x12, 0xc4, 0xd5, 0x0e, 0x15, 0x6f, 0x6c, 0xcb, 0x18, 0xbf, 0xe0, 0xe6, 0xbb, 0x45, - 0xcf, 0x5d, 0x49, 0x73, 0xb9, 0x18, 0x24, 0x51, 0xa7, 0xfa, 0xb8, 0x78, 0xbb, 0x13, 0x57, 0x6e, - 0x6e, 0x99, 0x50, 0x9c, 0xed, 0xd4, 0xd9, 0xaf, 0x59, 0x70, 0xba, 0x17, 0x09, 0x74, 0x12, 0x8a, - 0xbb, 0xa4, 0xc3, 0xb5, 0x32, 0x4c, 0x7f, 0xa2, 0x37, 0xa1, 0xb4, 0xe7, 0xf8, 0x6d, 0x22, 0xb4, - 0x9b, 0xe5, 0xa3, 0xbd, 0x88, 0xea, 0x19, 0xe6, 0x54, 0x7f, 0xb2, 0xf0, 0xb2, 0x65, 0xff, 0x9b, - 0x22, 0x8c, 0x1b, 0xfb, 0xdb, 0x03, 0xd0, 0xd8, 0xc2, 0x94, 0xc6, 0xb6, 0x96, 0xdb, 0xd6, 0xdc, - 0x57, 0x65, 0xbb, 0x9d, 0x51, 0xd9, 0xd6, 0xf3, 0x63, 0x79, 0x4f, 0x9d, 0x0d, 0x25, 0x50, 0x09, - 0x5b, 0x54, 0x23, 0xa7, 0x5b, 0xff, 0x48, 0x1e, 0x9f, 0x70, 0x5d, 0x92, 0xab, 0x4e, 0xde, 0x39, - 0x98, 0xad, 0xa8, 0xbf, 0x58, 0x33, 0xb2, 0x7f, 0x60, 0xc1, 0x69, 0xa3, 0x8f, 0x8b, 0x61, 0x50, - 0xf3, 0xd8, 0xa7, 0x3d, 0x0f, 0x23, 0x49, 0xa7, 0x25, 0xd5, 0x7e, 0x35, 0x52, 0x5b, 0x9d, 0x16, - 0xc1, 0x0c, 0x42, 0x15, 0xfd, 0x26, 0x89, 0x63, 0xa7, 0x41, 0xb2, 0x8a, 0xfe, 0x1a, 0x6f, 0xc6, - 0x12, 0x8e, 0x22, 0x40, 0xbe, 0x13, 0x27, 0x5b, 0x91, 0x13, 0xc4, 0x8c, 0xfc, 0x96, 0xd7, 0x24, - 0x62, 0x80, 0xff, 0xbf, 0xc1, 0x66, 0x0c, 0x7d, 0xa2, 0xfa, 0xd8, 0x9d, 0x83, 0x59, 0xb4, 0xda, - 0x45, 0x09, 0xf7, 0xa0, 0x6e, 0xff, 0xaa, 0x05, 0x8f, 0xf5, 0xd6, 0xc5, 0xd0, 0xb3, 0x30, 0xca, - 0x4d, 0x3e, 0xf1, 0x76, 0xfa, 0x93, 0xb0, 0x56, 0x2c, 0xa0, 0x68, 0x1e, 0x2a, 0x6a, 0x9f, 0x10, - 0xef, 0x38, 0x2d, 0x50, 0x2b, 0x7a, 0x73, 0xd1, 0x38, 0x74, 0xd0, 0xe8, 0x1f, 0xa1, 0xb9, 0xa9, - 0x41, 0x63, 0x46, 0x12, 0x83, 0xd8, 0x7f, 0x6e, 0xc1, 0x09, 0xa3, 0x57, 0x0f, 0x40, 0x35, 0x0f, - 0xd2, 0xaa, 0xf9, 0x4a, 0x6e, 0xf3, 0xb9, 0x8f, 0x6e, 0xfe, 0x0d, 0x0b, 0xce, 0x1a, 0x58, 0x6b, - 0x4e, 0xe2, 0xee, 0x5c, 0xdc, 0x6f, 0x45, 0x24, 0xa6, 0xe6, 0x34, 0x7a, 0xda, 0x90, 0x5b, 0xd5, - 0x71, 0x41, 0xa1, 0x78, 0x95, 0x74, 0xb8, 0x10, 0x7b, 0x1e, 0xca, 0x7c, 0x72, 0x86, 0x91, 0x18, - 0x71, 0xf5, 0x6e, 0xeb, 0xa2, 0x1d, 0x2b, 0x0c, 0x64, 0xc3, 0x28, 0x13, 0x4e, 0x74, 0xb1, 0xd2, - 0x6d, 0x08, 0xe8, 0x47, 0xbc, 0xc1, 0x5a, 0xb0, 0x80, 0xd8, 0x77, 0x0a, 0xcc, 0x56, 0x50, 0xab, - 0x90, 0x3c, 0x08, 0x43, 0x33, 0x4a, 0x89, 0xad, 0x8d, 0xfc, 0x64, 0x08, 0xe9, 0x6f, 0x6c, 0xbe, - 0x9d, 0x91, 0x5c, 0x38, 0x57, 0xae, 0xf7, 0x36, 0x38, 0x7f, 0xa3, 0x00, 0xb3, 0xe9, 0x07, 0xba, - 0x04, 0x1f, 0xb5, 0x6e, 0x0c, 0x46, 0xd9, 0xf3, 0x04, 0x03, 0x1f, 0x9b, 0x78, 0x7d, 0x64, 0x47, - 0xe1, 0x38, 0x65, 0x87, 0x29, 0xda, 0x8a, 0x87, 0x88, 0xb6, 0x67, 0xd5, 0xa8, 0x97, 0x32, 0xb2, - 0x24, 0x3d, 0x42, 0xff, 0xb5, 0x00, 0x8f, 0xa7, 0x47, 0x48, 0xcb, 0xda, 0x4f, 0xa6, 0x64, 0xed, - 0x47, 0x4d, 0x59, 0x7b, 0xf7, 0x60, 0xf6, 0xc9, 0x3e, 0x8f, 0xfd, 0xc8, 0x88, 0x62, 0xb4, 0xac, - 0xc6, 0x68, 0x84, 0xf5, 0x6e, 0x3e, 0x3d, 0x46, 0x77, 0x0f, 0x66, 0x9f, 0xee, 0xf3, 0x8e, 0x99, - 0x3d, 0xf2, 0x59, 0x18, 0x8d, 0x88, 0x13, 0x87, 0x41, 0x76, 0xb0, 0x31, 0x6b, 0xc5, 0x02, 0x6a, - 0xff, 0x79, 0x39, 0x3b, 0xd8, 0xcb, 0xfc, 0xb4, 0x2b, 0x8c, 0x90, 0x07, 0x23, 0x4c, 0x7f, 0xe6, - 0x0b, 0xff, 0xea, 0xd1, 0x16, 0x09, 0x95, 0xb7, 0x8a, 0x74, 0xb5, 0x4c, 0xbf, 0x1a, 0x6d, 0xc2, - 0x8c, 0x05, 0xda, 0x87, 0xb2, 0x2b, 0xd5, 0xda, 0x42, 0x1e, 0x07, 0x40, 0x42, 0xa9, 0xd5, 0x1c, - 0x27, 0xa8, 0x60, 0x54, 0xba, 0xb0, 0xe2, 0x86, 0x08, 0x14, 0x1b, 0x5e, 0x22, 0x3e, 0xeb, 0x11, - 0x0d, 0x97, 0x65, 0xcf, 0x78, 0xc5, 0x31, 0x2a, 0xad, 0x97, 0xbd, 0x04, 0x53, 0xfa, 0xe8, 0x97, - 0x2c, 0x18, 0x8f, 0xdd, 0xe6, 0x46, 0x14, 0xee, 0x79, 0x35, 0x12, 0x09, 0xb5, 0xe5, 0x88, 0x82, - 0x67, 0x73, 0x71, 0x4d, 0x12, 0xd4, 0x7c, 0xb9, 0x21, 0xa9, 0x21, 0xd8, 0xe4, 0x4b, 0xd5, 0xf9, - 0xc7, 0xc5, 0xbb, 0x2f, 0x11, 0xd7, 0xa3, 0x1b, 0x8d, 0xb4, 0x5e, 0xd8, 0x4c, 0x39, 0xb2, 0x1a, - 0xb7, 0xd4, 0x76, 0x77, 0xe9, 0x7a, 0xd3, 0x1d, 0x7a, 0xf2, 0xce, 0xc1, 0xec, 0xe3, 0x8b, 0xbd, - 0x79, 0xe2, 0x7e, 0x9d, 0x61, 0x03, 0xd6, 0x6a, 0xfb, 0x3e, 0x26, 0x6f, 0xb5, 0x09, 0x3b, 0x9b, - 0xc8, 0x61, 0xc0, 0x36, 0x34, 0xc1, 0xcc, 0x80, 0x19, 0x10, 0x6c, 0xf2, 0x45, 0x6f, 0xc1, 0x68, - 0xd3, 0x49, 0x22, 0x6f, 0x5f, 0x1c, 0x48, 0x1c, 0x51, 0xb1, 0x5e, 0x63, 0xb4, 0x34, 0x73, 0xb6, - 0x0f, 0xf3, 0x46, 0x2c, 0x18, 0xa1, 0x26, 0x94, 0x9a, 0x24, 0x6a, 0x90, 0x99, 0x72, 0x1e, 0x87, - 0xaf, 0x6b, 0x94, 0x94, 0x66, 0x58, 0xa1, 0x6a, 0x08, 0x6b, 0xc3, 0x9c, 0x0b, 0x7a, 0x13, 0xca, - 0x31, 0xf1, 0x89, 0x4b, 0x15, 0x89, 0x0a, 0xe3, 0xf8, 0xb1, 0x01, 0x95, 0x2a, 0x67, 0x9b, 0xf8, - 0x9b, 0xe2, 0x51, 0xbe, 0xc0, 0xe4, 0x3f, 0xac, 0x48, 0xda, 0xff, 0xc9, 0x02, 0x94, 0x96, 0x30, - 0x0f, 0x40, 0x95, 0x7b, 0x2b, 0xad, 0xca, 0xad, 0xe6, 0xb9, 0xc1, 0xf7, 0xd1, 0xe6, 0xde, 0x2b, - 0x43, 0x46, 0x36, 0x5f, 0x23, 0x71, 0x42, 0x6a, 0x1f, 0xc8, 0xd3, 0x0f, 0xe4, 0xe9, 0x07, 0xf2, - 0x54, 0xc9, 0xd3, 0xed, 0x8c, 0x3c, 0x7d, 0xd5, 0x58, 0xf5, 0xda, 0x95, 0xf8, 0x59, 0xe5, 0x6b, - 0x34, 0x7b, 0x60, 0x20, 0x50, 0x49, 0x70, 0x65, 0x73, 0xfd, 0x5a, 0x4f, 0x01, 0xfa, 0xd9, 0xb4, - 0x00, 0x3d, 0x2a, 0x8b, 0x07, 0x2e, 0x32, 0xff, 0x46, 0x01, 0x9e, 0x48, 0x8b, 0x12, 0x1c, 0xfa, - 0x7e, 0xd8, 0x4e, 0x36, 0x13, 0xd2, 0x42, 0xbf, 0x6e, 0xc1, 0xc9, 0x66, 0xda, 0x56, 0x8c, 0xc5, - 0x91, 0xdc, 0xa7, 0x72, 0x93, 0x73, 0x19, 0x63, 0xb4, 0x3a, 0x23, 0x64, 0xde, 0xc9, 0x0c, 0x20, - 0xc6, 0x5d, 0x7d, 0x41, 0x6f, 0x42, 0xa5, 0xe9, 0xec, 0x5f, 0x6f, 0xd5, 0x9c, 0x44, 0x9a, 0x1f, - 0xfd, 0xad, 0xc6, 0x76, 0xe2, 0xf9, 0x73, 0xdc, 0xd1, 0x3a, 0xb7, 0x12, 0x24, 0xeb, 0xd1, 0x66, - 0x12, 0x79, 0x41, 0x83, 0x1f, 0xc4, 0xac, 0x49, 0x32, 0x58, 0x53, 0xb4, 0xff, 0x96, 0x95, 0x15, - 0xb4, 0x6a, 0x74, 0x22, 0x27, 0x21, 0x8d, 0x0e, 0xfa, 0x3c, 0x94, 0xe2, 0x84, 0xb4, 0xe4, 0xa8, - 0xdc, 0xcc, 0x53, 0xfa, 0x1b, 0x5f, 0x42, 0x6f, 0x04, 0xf4, 0x5f, 0x8c, 0x39, 0x53, 0xfb, 0xce, - 0x48, 0x76, 0xc3, 0x63, 0x6e, 0xb7, 0x0b, 0x00, 0x8d, 0x70, 0x8b, 0x34, 0x5b, 0x3e, 0x1d, 0x16, - 0x8b, 0x9d, 0xdd, 0x2a, 0xd3, 0x78, 0x59, 0x41, 0xb0, 0x81, 0x85, 0xfe, 0x8a, 0x05, 0xd0, 0x90, - 0x0b, 0x4b, 0x6e, 0x66, 0xd7, 0xf3, 0x7c, 0x1d, 0xbd, 0x6c, 0x75, 0x5f, 0x14, 0x43, 0x6c, 0x30, - 0x47, 0x5f, 0xb6, 0xa0, 0x9c, 0xc8, 0xee, 0x73, 0xf1, 0xbe, 0x95, 0x67, 0x4f, 0xe4, 0x4b, 0xeb, - 0x7d, 0x5d, 0x0d, 0x89, 0xe2, 0x8b, 0x7e, 0xd9, 0x02, 0x88, 0x3b, 0x81, 0xbb, 0x11, 0xfa, 0x9e, - 0xdb, 0x11, 0x52, 0xff, 0x46, 0xae, 0xe6, 0xbb, 0xa2, 0x5e, 0x9d, 0xa2, 0xa3, 0xa1, 0xff, 0x63, - 0x83, 0x33, 0xfa, 0x02, 0x94, 0x63, 0x31, 0xdd, 0x84, 0x9c, 0xdf, 0xca, 0xf7, 0x10, 0x81, 0xd3, - 0x16, 0x22, 0x42, 0xfc, 0xc3, 0x8a, 0xa7, 0xfd, 0xbd, 0x42, 0xea, 0x34, 0x52, 0x9d, 0x3b, 0xb0, - 0x29, 0xe3, 0x4a, 0xa3, 0x50, 0xae, 0x80, 0x5c, 0xa7, 0x8c, 0x32, 0x39, 0xf5, 0x94, 0x51, 0x4d, - 0x31, 0x36, 0x98, 0xd3, 0xcd, 0x71, 0xda, 0xc9, 0x9e, 0x6e, 0x88, 0x59, 0xfc, 0x66, 0x9e, 0x5d, - 0xea, 0x3e, 0x3b, 0x7e, 0x42, 0x74, 0x6d, 0xba, 0x0b, 0x84, 0xbb, 0xbb, 0x64, 0x7f, 0x2f, 0x7d, - 0x02, 0x6a, 0x7c, 0x80, 0x01, 0x4e, 0x77, 0xbf, 0x69, 0xc1, 0x78, 0x14, 0xfa, 0xbe, 0x17, 0x34, - 0xe8, 0x64, 0x11, 0x12, 0xef, 0x8d, 0x63, 0x11, 0x3a, 0x62, 0x56, 0xb0, 0x2d, 0x16, 0x6b, 0x9e, - 0xd8, 0xec, 0x80, 0xfd, 0x25, 0x0b, 0x66, 0xfa, 0x4d, 0x6a, 0x44, 0xe0, 0x49, 0x2a, 0xa9, 0xe9, - 0xc6, 0xa7, 0x7c, 0x9b, 0xeb, 0xc1, 0x12, 0xf1, 0x89, 0x3a, 0x6b, 0x2a, 0x57, 0x9f, 0x11, 0xaf, - 0xf9, 0xe4, 0x46, 0x7f, 0x54, 0x7c, 0x2f, 0x3a, 0xf6, 0x6f, 0x17, 0xb2, 0x23, 0xaa, 0x84, 0xda, - 0xb7, 0xad, 0x2e, 0xd5, 0xff, 0x53, 0xc7, 0x21, 0x48, 0x98, 0x91, 0xa0, 0x5c, 0x9c, 0xfd, 0x71, - 0x1e, 0xa2, 0x0f, 0xc5, 0xfe, 0xd7, 0x23, 0x70, 0x8f, 0x9e, 0xa9, 0x53, 0x72, 0xab, 0xdf, 0x29, - 0xf9, 0xf0, 0x07, 0xef, 0x5f, 0xb7, 0x60, 0xd4, 0xa7, 0x5a, 0x08, 0x3f, 0x09, 0x1e, 0xbf, 0x50, - 0x3b, 0xae, 0xb1, 0xe7, 0xca, 0x4e, 0xcc, 0xfd, 0x78, 0xea, 0xfc, 0x89, 0x37, 0x62, 0xd1, 0x07, - 0xf4, 0x1d, 0x0b, 0xc6, 0x9d, 0x20, 0x08, 0x13, 0x11, 0x58, 0xc2, 0x03, 0x33, 0xbc, 0x63, 0xeb, - 0xd3, 0x82, 0xe6, 0xc5, 0x3b, 0xa6, 0x8f, 0x55, 0x35, 0x04, 0x9b, 0x5d, 0x42, 0x73, 0x00, 0x75, - 0x2f, 0x70, 0x7c, 0xef, 0x6d, 0x6a, 0x4d, 0x95, 0xd8, 0xf1, 0x39, 0xdb, 0x1a, 0x2e, 0xa9, 0x56, - 0x6c, 0x60, 0x9c, 0xfd, 0xcb, 0x30, 0x6e, 0xbc, 0x79, 0x0f, 0xf7, 0xe3, 0x69, 0xd3, 0xfd, 0x58, - 0x31, 0xbc, 0x86, 0x67, 0x5f, 0x85, 0x93, 0xd9, 0x0e, 0x0e, 0xf3, 0xbc, 0xfd, 0x3b, 0xa3, 0xd9, - 0xc3, 0xe5, 0x2d, 0x12, 0x35, 0x69, 0xd7, 0x3e, 0xb0, 0x42, 0x3f, 0xb0, 0x42, 0x3f, 0xb0, 0x42, - 0xe5, 0x1f, 0xfb, 0x4e, 0x09, 0x52, 0x9a, 0x01, 0xef, 0xdd, 0x47, 0x60, 0x2c, 0x22, 0xad, 0xf0, - 0x3a, 0x5e, 0x15, 0x12, 0x57, 0x07, 0x64, 0xf2, 0x66, 0x2c, 0xe1, 0x54, 0x32, 0xb7, 0x9c, 0x64, - 0x47, 0x88, 0x5c, 0x25, 0x99, 0x37, 0x9c, 0x64, 0x07, 0x33, 0x08, 0x7a, 0x15, 0xa6, 0x12, 0x27, - 0x6a, 0x90, 0x04, 0x93, 0x3d, 0x36, 0x08, 0xe2, 0x48, 0xff, 0x31, 0x81, 0x3b, 0xb5, 0x95, 0x82, - 0xe2, 0x0c, 0x36, 0x7a, 0x0b, 0x46, 0x76, 0x88, 0xdf, 0x14, 0x66, 0xf2, 0x66, 0x7e, 0x12, 0x91, - 0xbd, 0xeb, 0x65, 0xe2, 0x37, 0xf9, 0x7a, 0xa5, 0xbf, 0x30, 0x63, 0x45, 0xbf, 0x4e, 0x65, 0xb7, - 0x1d, 0x27, 0x61, 0xd3, 0x7b, 0x5b, 0x1a, 0xcf, 0x9f, 0xca, 0x99, 0xf1, 0x55, 0x49, 0x9f, 0x5b, - 0x78, 0xea, 0x2f, 0xd6, 0x9c, 0x59, 0x3f, 0x6a, 0x5e, 0xc4, 0x8c, 0xe1, 0xce, 0x0c, 0x1c, 0x4b, - 0x3f, 0x96, 0x24, 0x7d, 0xde, 0x0f, 0xf5, 0x17, 0x6b, 0xce, 0xa8, 0x03, 0xa3, 0x2d, 0xbf, 0xdd, - 0xf0, 0x82, 0x99, 0x71, 0xd6, 0x87, 0xeb, 0x39, 0xf7, 0x61, 0x83, 0x11, 0xe7, 0x47, 0x18, 0xfc, - 0x37, 0x16, 0x0c, 0xd1, 0x33, 0x50, 0x72, 0x77, 0x9c, 0x28, 0x99, 0x99, 0x60, 0x93, 0x46, 0x59, - 0x9a, 0x8b, 0xb4, 0x11, 0x73, 0x18, 0x7a, 0x1a, 0x8a, 0x11, 0xa9, 0xb3, 0x38, 0x20, 0xc3, 0x43, - 0x8c, 0x49, 0x1d, 0xd3, 0x76, 0xfb, 0x6f, 0x17, 0xd2, 0xca, 0x45, 0xfa, 0xbd, 0xf9, 0x6c, 0x77, - 0xdb, 0x51, 0x2c, 0xad, 0x51, 0x63, 0xb6, 0xb3, 0x66, 0x2c, 0xe1, 0xe8, 0x4b, 0x16, 0x8c, 0xdd, - 0x8a, 0xc3, 0x20, 0x20, 0x89, 0x10, 0xe4, 0x37, 0x72, 0x1e, 0x8a, 0x2b, 0x9c, 0xba, 0xee, 0x83, - 0x68, 0xc0, 0x92, 0x2f, 0xed, 0x2e, 0xd9, 0x77, 0xfd, 0x76, 0xad, 0xcb, 0xd3, 0x78, 0x91, 0x37, - 0x63, 0x09, 0xa7, 0xa8, 0x5e, 0xc0, 0x51, 0x47, 0xd2, 0xa8, 0x2b, 0x81, 0x40, 0x15, 0x70, 0xfb, - 0xf7, 0x4a, 0x70, 0xa6, 0xe7, 0xe2, 0xa0, 0xdb, 0x3e, 0xdb, 0x58, 0x2f, 0x79, 0x3e, 0x91, 0x51, - 0xb2, 0x6c, 0xdb, 0xbf, 0xa1, 0x5a, 0xb1, 0x81, 0x81, 0x7e, 0x01, 0xa0, 0xe5, 0x44, 0x4e, 0x93, - 0x88, 0xed, 0xae, 0x78, 0xf4, 0xdd, 0x95, 0xf6, 0x63, 0x43, 0xd2, 0xd4, 0xd6, 0x96, 0x6a, 0x8a, - 0xb1, 0xc1, 0x12, 0x7d, 0x1c, 0xc6, 0x23, 0xe2, 0x13, 0x27, 0x66, 0x61, 0x64, 0xd9, 0x98, 0x58, - 0xac, 0x41, 0xd8, 0xc4, 0x43, 0xcf, 0xaa, 0xc8, 0x80, 0x91, 0xb4, 0xa7, 0x30, 0x1d, 0x1d, 0x80, - 0xde, 0xb1, 0x60, 0xaa, 0xee, 0xf9, 0x44, 0x73, 0x17, 0x11, 0xac, 0xeb, 0x47, 0x7f, 0xc9, 0x4b, - 0x26, 0x5d, 0x2d, 0x21, 0x53, 0xcd, 0x31, 0xce, 0xb0, 0xa7, 0x9f, 0x79, 0x8f, 0x44, 0x4c, 0xb4, - 0x8e, 0xa6, 0x3f, 0xf3, 0x0d, 0xde, 0x8c, 0x25, 0x1c, 0x2d, 0xc0, 0x89, 0x96, 0x13, 0xc7, 0x8b, - 0x11, 0xa9, 0x91, 0x20, 0xf1, 0x1c, 0x9f, 0xc7, 0x97, 0x96, 0x75, 0x7c, 0xd9, 0x46, 0x1a, 0x8c, - 0xb3, 0xf8, 0xe8, 0xd3, 0xf0, 0xb8, 0xd7, 0x08, 0xc2, 0x88, 0xac, 0x79, 0x71, 0xec, 0x05, 0x0d, - 0x3d, 0x0d, 0x98, 0xa4, 0x2c, 0x57, 0x67, 0x05, 0xa9, 0xc7, 0x57, 0x7a, 0xa3, 0xe1, 0x7e, 0xcf, - 0xa3, 0xe7, 0xa1, 0x1c, 0xef, 0x7a, 0xad, 0xc5, 0xa8, 0x16, 0xb3, 0xe3, 0xc4, 0xb2, 0x3e, 0x03, - 0xd9, 0x14, 0xed, 0x58, 0x61, 0xd8, 0xbf, 0x56, 0x48, 0x9b, 0x77, 0xe6, 0xfa, 0x41, 0x31, 0x5d, - 0x25, 0xc9, 0x0d, 0x27, 0x92, 0xa6, 0xff, 0x11, 0x23, 0x54, 0x05, 0xdd, 0x1b, 0x4e, 0x64, 0xae, - 0x37, 0xc6, 0x00, 0x4b, 0x4e, 0xe8, 0x16, 0x8c, 0x24, 0xbe, 0x93, 0x53, 0x48, 0xbb, 0xc1, 0x51, - 0x5b, 0xdb, 0xab, 0x0b, 0x31, 0x66, 0x3c, 0xd0, 0x53, 0x54, 0x7d, 0xdd, 0x96, 0x61, 0x2c, 0x42, - 0xe3, 0xdc, 0x8e, 0x31, 0x6b, 0xb5, 0xff, 0xfb, 0x68, 0x0f, 0x91, 0xa7, 0xf6, 0x18, 0x74, 0x01, - 0x80, 0x5a, 0x42, 0x1b, 0x11, 0xa9, 0x7b, 0xfb, 0x62, 0x8f, 0x57, 0xcb, 0xea, 0x9a, 0x82, 0x60, - 0x03, 0x4b, 0x3e, 0xb3, 0xd9, 0xae, 0xd3, 0x67, 0x0a, 0xdd, 0xcf, 0x70, 0x08, 0x36, 0xb0, 0xd0, - 0x4b, 0x30, 0xea, 0x35, 0x9d, 0x86, 0x8a, 0xb6, 0x79, 0x8a, 0xae, 0xa7, 0x15, 0xd6, 0x72, 0xf7, - 0x60, 0x76, 0x4a, 0x75, 0x88, 0x35, 0x61, 0x81, 0x8b, 0x7e, 0xdb, 0x82, 0x09, 0x37, 0x6c, 0x36, - 0xc3, 0x80, 0xdb, 0x0f, 0xc2, 0x18, 0xba, 0x75, 0x5c, 0x3b, 0xf0, 0xdc, 0xa2, 0xc1, 0x8c, 0x5b, - 0x43, 0x2a, 0xf6, 0xde, 0x04, 0xe1, 0x54, 0xaf, 0xcc, 0x65, 0x57, 0x3a, 0x64, 0xd9, 0xfd, 0x63, - 0x0b, 0xa6, 0xf9, 0xb3, 0x86, 0x59, 0x23, 0xc2, 0xcc, 0xc3, 0x63, 0x7e, 0xad, 0x2e, 0x4b, 0x4f, - 0x1d, 0x09, 0x75, 0xc1, 0x71, 0x77, 0x27, 0xd1, 0x32, 0x4c, 0xd7, 0xc3, 0xc8, 0x25, 0xe6, 0x40, - 0x08, 0x99, 0xa1, 0x08, 0x5d, 0xca, 0x22, 0xe0, 0xee, 0x67, 0xd0, 0x0d, 0x78, 0xcc, 0x68, 0x34, - 0xc7, 0x81, 0x8b, 0x8d, 0x73, 0x82, 0xda, 0x63, 0x97, 0x7a, 0x62, 0xe1, 0x3e, 0x4f, 0x9f, 0xfd, - 0x24, 0x4c, 0x77, 0x7d, 0xbf, 0xa1, 0x8c, 0xcd, 0x25, 0x78, 0xac, 0xf7, 0x48, 0x0d, 0x65, 0x72, - 0xfe, 0xc3, 0x4c, 0xb4, 0x8e, 0xa1, 0xd8, 0x0c, 0x70, 0x7c, 0xe1, 0x40, 0x91, 0x04, 0x7b, 0x42, - 0x70, 0x5c, 0x3a, 0xda, 0x8c, 0xb8, 0x18, 0xec, 0xf1, 0x0f, 0xcd, 0x6c, 0xb4, 0x8b, 0xc1, 0x1e, - 0xa6, 0xb4, 0xd1, 0xbb, 0x56, 0x6a, 0x63, 0xe6, 0x87, 0x1e, 0x9f, 0x39, 0x16, 0x4d, 0x6e, 0xe0, - 0xbd, 0xda, 0xfe, 0x5e, 0x01, 0xce, 0x1f, 0x46, 0x64, 0x80, 0xe1, 0x7b, 0x06, 0x46, 0x63, 0xe6, - 0x2e, 0x11, 0x2b, 0x71, 0x9c, 0xae, 0x42, 0xee, 0x40, 0xf9, 0x2c, 0x16, 0x20, 0xf4, 0xcb, 0x16, - 0x14, 0x9b, 0x4e, 0x4b, 0xbc, 0x79, 0xe3, 0x78, 0xdf, 0x7c, 0x6e, 0xcd, 0x69, 0xf1, 0xaf, 0xa0, - 0xf4, 0xd1, 0x35, 0xa7, 0x85, 0x69, 0x07, 0xd0, 0x2c, 0x94, 0x9c, 0x28, 0x72, 0x3a, 0x4c, 0xae, - 0x55, 0xb8, 0x5b, 0x6d, 0x81, 0x36, 0x60, 0xde, 0x7e, 0xf6, 0x13, 0x50, 0x96, 0x8f, 0x0f, 0x35, - 0x07, 0xbf, 0x3e, 0x96, 0x0a, 0x15, 0x65, 0xee, 0x96, 0x18, 0x46, 0x85, 0x01, 0x6c, 0xe5, 0x1d, - 0x9d, 0xcc, 0x63, 0xfd, 0x99, 0xd6, 0x2e, 0x32, 0xa6, 0x04, 0x2b, 0xf4, 0x35, 0x8b, 0xe5, 0x25, - 0xc9, 0xf0, 0x59, 0xa1, 0x2b, 0x1f, 0x4f, 0x9a, 0x94, 0x99, 0xed, 0x24, 0x1b, 0xb1, 0xc9, 0x9d, - 0x0a, 0xea, 0x16, 0x8f, 0xb0, 0xcf, 0x6a, 0xcc, 0x32, 0x73, 0x49, 0xc2, 0xd1, 0x7e, 0x0f, 0xb7, - 0x4a, 0x0e, 0xb9, 0x2d, 0x03, 0x38, 0x52, 0xbe, 0x63, 0xc1, 0x34, 0xd7, 0x8b, 0x96, 0xbc, 0x7a, - 0x9d, 0x44, 0x24, 0x70, 0x89, 0xd4, 0x2c, 0x8f, 0xe8, 0xb8, 0x93, 0xa7, 0x0e, 0x2b, 0x59, 0xf2, - 0x5a, 0x82, 0x77, 0x81, 0x70, 0x77, 0x67, 0x50, 0x0d, 0x46, 0xbc, 0xa0, 0x1e, 0x8a, 0x7d, 0xab, - 0x7a, 0xb4, 0x4e, 0xad, 0x04, 0xf5, 0x50, 0xaf, 0x65, 0xfa, 0x0f, 0x33, 0xea, 0x68, 0x15, 0x4e, - 0x47, 0xc2, 0xf6, 0xbf, 0xec, 0xc5, 0xd4, 0x42, 0x5b, 0xf5, 0x9a, 0x5e, 0xc2, 0xf6, 0x9c, 0x62, - 0x75, 0xe6, 0xce, 0xc1, 0xec, 0x69, 0xdc, 0x03, 0x8e, 0x7b, 0x3e, 0x85, 0xde, 0x86, 0x31, 0x99, - 0x48, 0x55, 0xce, 0x43, 0x4b, 0xef, 0x9e, 0xff, 0x6a, 0x32, 0x6d, 0x8a, 0x9c, 0x29, 0xc9, 0xd0, - 0xfe, 0xe7, 0x00, 0xdd, 0x6e, 0x17, 0xf4, 0xf3, 0x50, 0x89, 0x54, 0x72, 0x97, 0x95, 0x47, 0x58, - 0x8e, 0xfc, 0xbe, 0xc2, 0xe5, 0xa3, 0xce, 0xbd, 0x75, 0x1a, 0x97, 0xe6, 0x48, 0x75, 0xd4, 0x58, - 0x7b, 0x67, 0x72, 0x98, 0xdb, 0x82, 0xab, 0x3e, 0xd5, 0xef, 0x04, 0x2e, 0x66, 0x3c, 0x50, 0x04, - 0xa3, 0x3b, 0xc4, 0xf1, 0x93, 0x9d, 0x7c, 0x0e, 0x20, 0x2f, 0x33, 0x5a, 0xd9, 0xb8, 0x62, 0xde, - 0x8a, 0x05, 0x27, 0xb4, 0x0f, 0x63, 0x3b, 0x7c, 0x02, 0x08, 0xb5, 0x71, 0xed, 0xa8, 0x83, 0x9b, - 0x9a, 0x55, 0xfa, 0x73, 0x8b, 0x06, 0x2c, 0xd9, 0x31, 0x9f, 0xac, 0xe1, 0x71, 0xe4, 0x4b, 0x37, - 0xbf, 0x90, 0xea, 0xc1, 0xdd, 0x8d, 0x9f, 0x83, 0x89, 0x88, 0xb8, 0x61, 0xe0, 0x7a, 0x3e, 0xa9, - 0x2d, 0xc8, 0xc3, 0xc5, 0x61, 0x42, 0x75, 0x4f, 0x52, 0xd5, 0x17, 0x1b, 0x34, 0x70, 0x8a, 0x22, - 0xfa, 0xaa, 0x05, 0x53, 0x2a, 0x23, 0x84, 0x7e, 0x10, 0x22, 0x8e, 0xe7, 0x56, 0x73, 0xca, 0x3f, - 0x61, 0x34, 0xab, 0x88, 0x1a, 0xbf, 0xe9, 0x36, 0x9c, 0xe1, 0x8b, 0x5e, 0x07, 0x08, 0xb7, 0x99, - 0xfb, 0x8d, 0xbe, 0x6a, 0x79, 0xe8, 0x57, 0x9d, 0xe2, 0x11, 0xf9, 0x92, 0x02, 0x36, 0xa8, 0xa1, - 0xab, 0x00, 0x7c, 0xd9, 0x6c, 0x75, 0x5a, 0x84, 0x59, 0xa4, 0x3a, 0xd6, 0x1a, 0x36, 0x15, 0xe4, - 0xee, 0xc1, 0x6c, 0xf7, 0xd9, 0x09, 0x73, 0x8c, 0x1a, 0x8f, 0xa3, 0x9f, 0x83, 0xb1, 0xb8, 0xdd, - 0x6c, 0x3a, 0xea, 0x24, 0x2f, 0xc7, 0x18, 0x7f, 0x4e, 0xd7, 0x10, 0x45, 0xbc, 0x01, 0x4b, 0x8e, - 0xe8, 0x16, 0x15, 0xaa, 0xb1, 0x38, 0xd4, 0x61, 0xab, 0x88, 0xeb, 0x04, 0xe3, 0xec, 0x9d, 0x3e, - 0x21, 0x9e, 0x3b, 0x8d, 0x7b, 0xe0, 0xdc, 0x3d, 0x98, 0x7d, 0x2c, 0xdd, 0xbe, 0x1a, 0x8a, 0xa8, - 0xfb, 0x9e, 0x34, 0xd1, 0x15, 0x99, 0x57, 0x4d, 0x5f, 0x5b, 0xa6, 0xfb, 0x3d, 0xa7, 0xf3, 0xaa, - 0x59, 0x73, 0xff, 0x31, 0x33, 0x1f, 0xb6, 0x83, 0x74, 0x08, 0x89, 0x78, 0x9b, 0x97, 0x60, 0x82, - 0xec, 0x27, 0x24, 0x0a, 0x1c, 0xff, 0x3a, 0x5e, 0x95, 0x87, 0x52, 0x6c, 0xd2, 0x5e, 0x34, 0xda, - 0x71, 0x0a, 0x0b, 0xd9, 0xca, 0x18, 0x2d, 0xe8, 0xd4, 0x0f, 0x6e, 0x8c, 0x4a, 0xd3, 0xd3, 0xfe, - 0x3f, 0x85, 0x94, 0x06, 0xb5, 0x15, 0x11, 0x82, 0x42, 0x28, 0x05, 0x61, 0x4d, 0x09, 0xeb, 0x2b, - 0xf9, 0x08, 0xeb, 0x6b, 0x61, 0xcd, 0xc8, 0x96, 0xa6, 0xff, 0x62, 0xcc, 0xf9, 0xb0, 0x74, 0x52, - 0x99, 0x77, 0xcb, 0x00, 0xc2, 0x2e, 0xc8, 0x93, 0xb3, 0x4a, 0x27, 0x5d, 0x37, 0x19, 0xe1, 0x34, - 0x5f, 0xb4, 0x0b, 0xa5, 0x9d, 0x30, 0x4e, 0xa4, 0xb5, 0x70, 0x44, 0xc3, 0xe4, 0x72, 0x18, 0x27, - 0x6c, 0xdb, 0x57, 0xaf, 0x4d, 0x5b, 0x62, 0xcc, 0x79, 0xd8, 0xff, 0xd9, 0x4a, 0x1d, 0x41, 0xde, - 0x64, 0xe1, 0x54, 0x7b, 0x24, 0xa0, 0xeb, 0xd0, 0x8c, 0x3d, 0xf8, 0x4b, 0x99, 0x6c, 0x87, 0x0f, - 0xf7, 0xab, 0x5d, 0x71, 0x9b, 0x52, 0x98, 0x63, 0x24, 0x8c, 0x30, 0x85, 0x2f, 0x5a, 0xe9, 0xac, - 0x12, 0xbe, 0x11, 0xe6, 0x98, 0xe4, 0x74, 0x68, 0x82, 0x8a, 0xfd, 0xae, 0x05, 0x63, 0x55, 0xc7, - 0xdd, 0x0d, 0xeb, 0x75, 0xf4, 0x3c, 0x94, 0x6b, 0xed, 0xc8, 0x4c, 0x70, 0x51, 0x67, 0x5e, 0x4b, - 0xa2, 0x1d, 0x2b, 0x0c, 0x3a, 0x87, 0xeb, 0x8e, 0x2b, 0x53, 0x9d, 0x8a, 0x7c, 0x0e, 0x5f, 0x62, - 0x2d, 0x58, 0x40, 0xd0, 0xc7, 0x61, 0xbc, 0xe9, 0xec, 0xcb, 0x87, 0xb3, 0xe7, 0x9f, 0x6b, 0x1a, - 0x84, 0x4d, 0x3c, 0xfb, 0x5f, 0x5a, 0x30, 0x53, 0x75, 0x62, 0xcf, 0x5d, 0x68, 0x27, 0x3b, 0x55, - 0x2f, 0xd9, 0x6e, 0xbb, 0xbb, 0x24, 0xe1, 0xf9, 0x6d, 0xb4, 0x97, 0xed, 0x98, 0x2e, 0x25, 0x65, - 0x86, 0xa9, 0x5e, 0x5e, 0x17, 0xed, 0x58, 0x61, 0xa0, 0xb7, 0x61, 0xbc, 0xe5, 0xc4, 0xf1, 0xed, - 0x30, 0xaa, 0x61, 0x52, 0xcf, 0x27, 0xbb, 0x74, 0x93, 0xb8, 0x11, 0x49, 0x30, 0xa9, 0x0b, 0x8f, - 0x96, 0xa6, 0x8f, 0x4d, 0x66, 0xf6, 0xbf, 0xa8, 0xc0, 0x98, 0x70, 0xc7, 0x0d, 0x9c, 0xb5, 0x27, - 0x0d, 0xcc, 0x42, 0x5f, 0x03, 0x33, 0x86, 0x51, 0x97, 0xd5, 0x38, 0x11, 0x9a, 0xcc, 0xd5, 0x5c, - 0xfc, 0xb7, 0xbc, 0x6c, 0x8a, 0xee, 0x16, 0xff, 0x8f, 0x05, 0x2b, 0xf4, 0x2d, 0x0b, 0x4e, 0xb8, - 0x61, 0x10, 0x10, 0x57, 0x6f, 0xb3, 0x23, 0x79, 0x44, 0x64, 0x2c, 0xa6, 0x89, 0xea, 0xc3, 0xdf, - 0x0c, 0x00, 0x67, 0xd9, 0xa3, 0x57, 0x60, 0x92, 0x8f, 0xd9, 0x8d, 0xd4, 0xc9, 0x97, 0x4e, 0x4e, - 0x37, 0x81, 0x38, 0x8d, 0x8b, 0xe6, 0xf8, 0x09, 0xa2, 0x48, 0x03, 0x1f, 0xd5, 0x9e, 0x04, 0x23, - 0x01, 0xdc, 0xc0, 0x40, 0x11, 0xa0, 0x88, 0xd4, 0x23, 0x12, 0xef, 0x08, 0x77, 0x25, 0xdb, 0xe2, - 0xc7, 0xee, 0x2f, 0xf1, 0x08, 0x77, 0x51, 0xc2, 0x3d, 0xa8, 0xa3, 0x5d, 0x61, 0xe3, 0x94, 0xf3, - 0x90, 0x0a, 0xe2, 0x33, 0xf7, 0x35, 0x75, 0x66, 0xa1, 0x14, 0xef, 0x38, 0x51, 0x8d, 0xa9, 0x16, - 0x45, 0x7e, 0x10, 0xb0, 0x49, 0x1b, 0x30, 0x6f, 0x47, 0x4b, 0x70, 0x32, 0x93, 0x5a, 0x1f, 0x33, - 0xe5, 0xa1, 0xac, 0xe3, 0x50, 0x33, 0x49, 0xf9, 0x31, 0xee, 0x7a, 0xc2, 0xb4, 0x7f, 0xc7, 0x0f, - 0xb1, 0x7f, 0x3b, 0x2a, 0x28, 0x66, 0x82, 0x49, 0xfc, 0xd7, 0x72, 0x19, 0x80, 0x81, 0x22, 0x60, - 0xbe, 0x91, 0x89, 0x80, 0x99, 0x64, 0x1d, 0xb8, 0x91, 0x4f, 0x07, 0x86, 0x0f, 0x77, 0x79, 0x98, - 0xe1, 0x2b, 0xff, 0xdb, 0x02, 0xf9, 0x5d, 0x17, 0x1d, 0x77, 0x87, 0xd0, 0x29, 0x83, 0x5e, 0x85, - 0x29, 0x65, 0xc5, 0x2d, 0x86, 0xed, 0x80, 0x47, 0xae, 0x14, 0xb5, 0x97, 0x08, 0xa7, 0xa0, 0x38, - 0x83, 0x8d, 0xe6, 0xa1, 0x42, 0xc7, 0x89, 0x3f, 0xca, 0x77, 0x0f, 0x65, 0x29, 0x2e, 0x6c, 0xac, - 0x88, 0xa7, 0x34, 0x0e, 0x0a, 0x61, 0xda, 0x77, 0xe2, 0x84, 0xf5, 0x80, 0x1a, 0x75, 0xf7, 0x99, - 0xf6, 0xc7, 0x2a, 0x8b, 0xac, 0x66, 0x09, 0xe1, 0x6e, 0xda, 0xf6, 0x0f, 0x46, 0x60, 0x32, 0x25, - 0x19, 0x87, 0xdc, 0x76, 0x9e, 0x87, 0xb2, 0xdc, 0x09, 0xb2, 0x99, 0xc0, 0x6a, 0xbb, 0x50, 0x18, - 0x74, 0x9b, 0xdc, 0x26, 0x4e, 0x44, 0x22, 0x56, 0xb4, 0x20, 0xbb, 0x4d, 0x56, 0x35, 0x08, 0x9b, - 0x78, 0x4c, 0x28, 0x27, 0x7e, 0xbc, 0xe8, 0x7b, 0x24, 0x48, 0x78, 0x37, 0xf3, 0x11, 0xca, 0x5b, - 0xab, 0x9b, 0x26, 0x51, 0x2d, 0x94, 0x33, 0x00, 0x9c, 0x65, 0x8f, 0xbe, 0x62, 0xc1, 0xa4, 0x73, - 0x3b, 0xd6, 0x85, 0xb8, 0x44, 0xac, 0xcb, 0x11, 0x37, 0xa9, 0x54, 0x6d, 0xaf, 0xea, 0x34, 0x15, - 0xef, 0xa9, 0x26, 0x9c, 0x66, 0x8a, 0xbe, 0x6d, 0x01, 0x22, 0xfb, 0xc4, 0x95, 0xd1, 0x38, 0xa2, - 0x2f, 0xa3, 0x79, 0x18, 0x3b, 0x17, 0xbb, 0xe8, 0x72, 0xa9, 0xde, 0xdd, 0x8e, 0x7b, 0xf4, 0xc1, - 0xfe, 0x27, 0x45, 0xb5, 0xa0, 0x74, 0x00, 0x98, 0x63, 0x24, 0x2f, 0x58, 0xf7, 0x9f, 0xbc, 0xa0, - 0x5d, 0x94, 0x5d, 0x09, 0x0c, 0xe9, 0x58, 0xf1, 0xc2, 0x43, 0x8a, 0x15, 0xff, 0xb2, 0x95, 0xca, - 0x79, 0x1f, 0xbf, 0xf0, 0x7a, 0xbe, 0xc1, 0x67, 0x73, 0xdc, 0x41, 0x9e, 0x91, 0xee, 0x69, 0xaf, - 0x39, 0x95, 0xa6, 0x06, 0xda, 0x50, 0xd2, 0xf0, 0xdf, 0x17, 0x61, 0xdc, 0xd8, 0x49, 0x7b, 0xaa, - 0x45, 0xd6, 0x23, 0xa6, 0x16, 0x15, 0x86, 0x50, 0x8b, 0x7e, 0x01, 0x2a, 0xae, 0x94, 0xf2, 0xf9, - 0x54, 0x7d, 0xcb, 0xee, 0x1d, 0x5a, 0xd0, 0xab, 0x26, 0xac, 0x79, 0xa2, 0xe5, 0x54, 0x74, 0xba, - 0xd8, 0x21, 0x46, 0xd8, 0x0e, 0xd1, 0x2b, 0x7c, 0x5c, 0xec, 0x14, 0xdd, 0xcf, 0xa0, 0x17, 0xa9, - 0x65, 0xe5, 0x89, 0xf7, 0x92, 0x21, 0xa2, 0x4c, 0x5d, 0x5f, 0xd8, 0x58, 0x91, 0xcd, 0xd8, 0xc4, - 0xb1, 0x7f, 0x60, 0xa9, 0x8f, 0xfb, 0x00, 0xd2, 0x21, 0x6f, 0xa5, 0xd3, 0x21, 0x2f, 0xe6, 0x32, - 0xcc, 0x7d, 0xf2, 0x20, 0xaf, 0xc1, 0xd8, 0x62, 0xd8, 0x6c, 0x3a, 0x41, 0x0d, 0xfd, 0x04, 0x8c, - 0xb9, 0xfc, 0xa7, 0x38, 0xaa, 0x60, 0xfe, 0x29, 0x01, 0xc5, 0x12, 0x86, 0x9e, 0x82, 0x11, 0x27, - 0x6a, 0xc8, 0xe3, 0x09, 0xe6, 0xd2, 0x5f, 0x88, 0x1a, 0x31, 0x66, 0xad, 0xf6, 0x3b, 0x45, 0x80, - 0xc5, 0xb0, 0xd9, 0x72, 0x22, 0x52, 0xdb, 0x0a, 0x59, 0xd5, 0x99, 0x63, 0xf5, 0xeb, 0x68, 0x63, - 0xe9, 0x51, 0xf6, 0xed, 0x18, 0xe7, 0xfb, 0xc5, 0x07, 0x7d, 0xbe, 0xff, 0x75, 0x0b, 0x10, 0xfd, - 0x22, 0x61, 0x40, 0x82, 0x44, 0xbb, 0x2b, 0xe7, 0xa1, 0xe2, 0xca, 0x56, 0xa1, 0xb5, 0xe8, 0xf5, - 0x27, 0x01, 0x58, 0xe3, 0x0c, 0x60, 0x7e, 0x3e, 0x23, 0x85, 0x63, 0x31, 0x1d, 0x05, 0xc7, 0x44, - 0xaa, 0x90, 0x95, 0xf6, 0x1f, 0x14, 0xe0, 0x31, 0xbe, 0xdf, 0xad, 0x39, 0x81, 0xd3, 0x20, 0x4d, - 0xda, 0xab, 0x41, 0x1d, 0xd0, 0x2e, 0xb5, 0x7b, 0x3c, 0x19, 0xd5, 0x76, 0xd4, 0x85, 0xc1, 0x27, - 0x34, 0x9f, 0xc2, 0x2b, 0x81, 0x97, 0x60, 0x46, 0x1c, 0xc5, 0x50, 0x96, 0x35, 0x44, 0x85, 0xa0, - 0xcb, 0x89, 0x91, 0x5a, 0xf3, 0x62, 0x53, 0x22, 0x58, 0x31, 0xa2, 0x5a, 0xa1, 0x1f, 0xba, 0xbb, - 0x98, 0xb4, 0x42, 0x26, 0xd4, 0x8c, 0xa0, 0xa2, 0x55, 0xd1, 0x8e, 0x15, 0x86, 0xfd, 0x07, 0x16, - 0x64, 0xc5, 0xbd, 0x51, 0xb0, 0xc3, 0xba, 0x57, 0xc1, 0x8e, 0x61, 0x6a, 0x6a, 0xfc, 0x2c, 0x8c, - 0x3b, 0x09, 0xdd, 0xa1, 0xb9, 0x4d, 0x5b, 0xbc, 0xbf, 0x63, 0xeb, 0xb5, 0xb0, 0xe6, 0xd5, 0x3d, - 0x66, 0xcb, 0x9a, 0xe4, 0xec, 0xff, 0x39, 0x02, 0xd3, 0x5d, 0x91, 0xca, 0xe8, 0x65, 0x98, 0x70, - 0xc5, 0xf4, 0x68, 0x61, 0x52, 0x17, 0x2f, 0x63, 0x44, 0xba, 0x68, 0x18, 0x4e, 0x61, 0x0e, 0x30, - 0x41, 0x57, 0xe0, 0x54, 0x44, 0xad, 0xe8, 0x36, 0x59, 0xa8, 0x27, 0x24, 0xda, 0x24, 0x6e, 0x18, - 0xd4, 0x78, 0x59, 0x99, 0x62, 0xf5, 0xf1, 0x3b, 0x07, 0xb3, 0xa7, 0x70, 0x37, 0x18, 0xf7, 0x7a, - 0x06, 0xb5, 0x60, 0xd2, 0x37, 0x15, 0x2c, 0xa1, 0x5d, 0xdf, 0x97, 0x6e, 0xa6, 0x36, 0xe0, 0x54, - 0x33, 0x4e, 0x33, 0x48, 0x6b, 0x69, 0xa5, 0x87, 0xa4, 0xa5, 0xfd, 0xa2, 0xd6, 0xd2, 0xb8, 0x7f, - 0xf5, 0x8d, 0x9c, 0x23, 0xd5, 0x8f, 0x5b, 0x4d, 0x7b, 0x0d, 0xca, 0x32, 0xf2, 0x64, 0xa0, 0x88, - 0x0d, 0x93, 0x4e, 0x1f, 0x89, 0x76, 0xb7, 0x00, 0x3d, 0x34, 0x7c, 0xba, 0xce, 0xf4, 0x76, 0x9a, - 0x5a, 0x67, 0xc3, 0x6d, 0xa9, 0x68, 0x9f, 0x47, 0xdd, 0xf0, 0x8d, 0xe3, 0xd3, 0x79, 0x5b, 0x28, - 0x3a, 0x10, 0x47, 0x85, 0x80, 0xa8, 0x60, 0x9c, 0x0b, 0x00, 0x5a, 0x0b, 0x12, 0x01, 0xa7, 0xca, - 0xad, 0xa7, 0x95, 0x25, 0x6c, 0x60, 0x51, 0x83, 0xd5, 0x0b, 0xe2, 0xc4, 0xf1, 0xfd, 0xcb, 0x5e, - 0x90, 0x88, 0x93, 0x37, 0xb5, 0x43, 0xae, 0x68, 0x10, 0x36, 0xf1, 0xce, 0x7e, 0xc2, 0xf8, 0x2e, - 0xc3, 0x7c, 0xcf, 0x1d, 0x78, 0x62, 0xd9, 0x4b, 0x54, 0x98, 0xb4, 0x9a, 0x47, 0x54, 0xc9, 0x51, - 0x61, 0xff, 0x56, 0xdf, 0xb0, 0x7f, 0x23, 0x4c, 0xb9, 0x90, 0x8e, 0xaa, 0xce, 0x86, 0x29, 0xdb, - 0x2f, 0xc3, 0xe9, 0x65, 0x2f, 0xb9, 0xe4, 0xf9, 0x64, 0x48, 0x26, 0xf6, 0x57, 0x4a, 0x30, 0x61, - 0xa6, 0xa5, 0x0c, 0x93, 0xb9, 0xf0, 0x4d, 0xaa, 0xc7, 0x88, 0xb7, 0xf3, 0x94, 0x8f, 0xe5, 0xe6, - 0x91, 0x73, 0x64, 0x7a, 0x8f, 0x98, 0xa1, 0xca, 0x68, 0x9e, 0xd8, 0xec, 0x00, 0xba, 0x0d, 0xa5, - 0x3a, 0x0b, 0xa3, 0x2d, 0xe6, 0xe1, 0x39, 0xee, 0x35, 0xa2, 0x7a, 0x99, 0xf1, 0x40, 0x5c, 0xce, - 0x8f, 0xee, 0x90, 0x51, 0x3a, 0x37, 0x43, 0x09, 0x2a, 0x95, 0x95, 0xa1, 0x30, 0xfa, 0x89, 0xfa, - 0xd2, 0x7d, 0x88, 0xfa, 0x94, 0xe0, 0x1d, 0x7d, 0x48, 0x82, 0x97, 0x85, 0x44, 0x27, 0x3b, 0x4c, - 0x7f, 0x13, 0x01, 0xb1, 0x63, 0x6c, 0x10, 0x8c, 0x90, 0xe8, 0x14, 0x18, 0x67, 0xf1, 0xed, 0xaf, - 0x17, 0x60, 0x6a, 0x39, 0x68, 0x6f, 0x2c, 0x6f, 0xb4, 0xb7, 0x7d, 0xcf, 0xbd, 0x4a, 0x3a, 0x54, - 0xbe, 0xed, 0x92, 0xce, 0xca, 0x92, 0x98, 0x86, 0x6a, 0xe0, 0xaf, 0xd2, 0x46, 0xcc, 0x61, 0x74, - 0x45, 0xd7, 0xbd, 0xa0, 0x41, 0xa2, 0x56, 0xe4, 0x89, 0x43, 0x39, 0x63, 0x45, 0x5f, 0xd2, 0x20, - 0x6c, 0xe2, 0x51, 0xda, 0xe1, 0xed, 0x80, 0x44, 0x59, 0x6d, 0x70, 0x9d, 0x36, 0x62, 0x0e, 0xa3, - 0x48, 0x49, 0xd4, 0x8e, 0x13, 0xf1, 0x45, 0x15, 0xd2, 0x16, 0x6d, 0xc4, 0x1c, 0x46, 0x97, 0x4b, - 0xdc, 0xde, 0x66, 0xde, 0xed, 0x4c, 0x08, 0xeb, 0x26, 0x6f, 0xc6, 0x12, 0x4e, 0x51, 0x77, 0x49, - 0x67, 0x89, 0xda, 0x65, 0x99, 0x20, 0xf3, 0xab, 0xbc, 0x19, 0x4b, 0x38, 0xab, 0x74, 0x93, 0x1e, - 0x8e, 0x1f, 0xb9, 0x4a, 0x37, 0xe9, 0xee, 0xf7, 0xb1, 0xf0, 0x7e, 0xd3, 0x82, 0x09, 0x33, 0x26, - 0x05, 0x35, 0x32, 0x8a, 0xe2, 0x7a, 0x57, 0xd5, 0xb2, 0x9f, 0xee, 0x75, 0x5f, 0x42, 0xc3, 0x4b, - 0xc2, 0x56, 0xfc, 0x02, 0x09, 0x1a, 0x5e, 0x40, 0x98, 0xe7, 0x92, 0xc7, 0xb2, 0xa4, 0x02, 0x5e, - 0x16, 0xc3, 0x1a, 0xb9, 0x0f, 0x4d, 0xd3, 0xbe, 0x09, 0xd3, 0x5d, 0x99, 0x05, 0x03, 0xec, 0xcf, - 0x87, 0xe6, 0x75, 0xd9, 0x18, 0xc6, 0x29, 0xe1, 0xf5, 0x16, 0x0f, 0x3a, 0x59, 0x84, 0x69, 0xae, - 0x43, 0x50, 0x4e, 0x9b, 0xee, 0x0e, 0x69, 0xaa, 0x6c, 0x11, 0x76, 0x02, 0x7c, 0x23, 0x0b, 0xc4, - 0xdd, 0xf8, 0xf6, 0x37, 0x2c, 0x98, 0x4c, 0x25, 0x7b, 0xe4, 0xa4, 0x49, 0xb0, 0x95, 0x16, 0xb2, - 0x10, 0x29, 0x16, 0x25, 0x5a, 0x64, 0x3b, 0x92, 0x5e, 0x69, 0x1a, 0x84, 0x4d, 0x3c, 0xfb, 0xdd, - 0x02, 0x94, 0xa5, 0xd7, 0x7a, 0x80, 0xae, 0x7c, 0xcd, 0x82, 0x49, 0x75, 0xea, 0xce, 0x8e, 0x73, - 0xf8, 0x64, 0xbc, 0x76, 0x74, 0xbf, 0xb9, 0x8a, 0xe1, 0x0b, 0xea, 0xa1, 0x56, 0x6b, 0xb1, 0xc9, - 0x0c, 0xa7, 0x79, 0xa3, 0x1b, 0x00, 0x71, 0x27, 0x4e, 0x48, 0xd3, 0x38, 0x58, 0xb2, 0x8d, 0x15, - 0x37, 0xe7, 0x86, 0x11, 0xa1, 0xeb, 0xeb, 0x5a, 0x58, 0x23, 0x9b, 0x0a, 0x53, 0xeb, 0x21, 0xba, - 0x0d, 0x1b, 0x94, 0xec, 0xbf, 0x5f, 0x80, 0x93, 0xd9, 0x2e, 0xa1, 0x37, 0x60, 0x42, 0x72, 0x37, - 0xee, 0x7e, 0x90, 0xae, 0xfa, 0x09, 0x6c, 0xc0, 0xee, 0x1e, 0xcc, 0xce, 0x76, 0xdf, 0xbd, 0x31, - 0x67, 0xa2, 0xe0, 0x14, 0x31, 0xee, 0xfa, 0x10, 0x3e, 0xba, 0x6a, 0x67, 0xa1, 0xd5, 0x12, 0xfe, - 0x0b, 0xc3, 0xf5, 0x61, 0x42, 0x71, 0x06, 0x1b, 0x6d, 0xc0, 0x69, 0xa3, 0xe5, 0x1a, 0xf1, 0x1a, - 0x3b, 0xdb, 0x61, 0x24, 0xcd, 0x93, 0xa7, 0x74, 0xf4, 0x4b, 0x37, 0x0e, 0xee, 0xf9, 0x24, 0xdd, - 0x32, 0x5d, 0xa7, 0xe5, 0xb8, 0x5e, 0xd2, 0x11, 0x27, 0x65, 0x4a, 0x36, 0x2d, 0x8a, 0x76, 0xac, - 0x30, 0xec, 0x35, 0x18, 0x19, 0x70, 0x06, 0x0d, 0xa4, 0x16, 0xbf, 0x06, 0x65, 0x4a, 0x4e, 0xea, - 0x48, 0x79, 0x90, 0x0c, 0xa1, 0x2c, 0xcb, 0x37, 0x23, 0x1b, 0x8a, 0x9e, 0x23, 0xbd, 0x4b, 0xea, - 0xb5, 0x56, 0xe2, 0xb8, 0xcd, 0x2c, 0x4d, 0x0a, 0x44, 0xcf, 0x40, 0x91, 0xec, 0xb7, 0xb2, 0x6e, - 0xa4, 0x8b, 0xfb, 0x2d, 0x2f, 0x22, 0x31, 0x45, 0x22, 0xfb, 0x2d, 0x74, 0x16, 0x0a, 0x5e, 0x4d, - 0x6c, 0x52, 0x20, 0x70, 0x0a, 0x2b, 0x4b, 0xb8, 0xe0, 0xd5, 0xec, 0x7d, 0xa8, 0xa8, 0x7a, 0xd1, - 0x68, 0x57, 0xca, 0x6e, 0x2b, 0x8f, 0x30, 0x13, 0x49, 0xb7, 0x8f, 0xd4, 0x6e, 0x03, 0xe8, 0xd4, - 0x9a, 0xbc, 0xe4, 0xcb, 0x79, 0x18, 0x71, 0x43, 0x91, 0x91, 0x57, 0xd6, 0x64, 0x98, 0xd0, 0x66, - 0x10, 0xfb, 0x26, 0x4c, 0x5d, 0x0d, 0xc2, 0xdb, 0xac, 0x06, 0xe7, 0x25, 0x8f, 0xf8, 0x35, 0x4a, - 0xb8, 0x4e, 0x7f, 0x64, 0x55, 0x04, 0x06, 0xc5, 0x1c, 0xa6, 0xca, 0x6e, 0x14, 0xfa, 0x95, 0xdd, - 0xb0, 0xbf, 0x68, 0xc1, 0x49, 0x95, 0xf3, 0x21, 0xa5, 0xf1, 0xcb, 0x30, 0xb1, 0xdd, 0xf6, 0xfc, - 0x9a, 0xf8, 0x9f, 0xb5, 0xf5, 0xab, 0x06, 0x0c, 0xa7, 0x30, 0xa9, 0x65, 0xb2, 0xed, 0x05, 0x4e, - 0xd4, 0xd9, 0xd0, 0xe2, 0x5f, 0x49, 0x84, 0xaa, 0x82, 0x60, 0x03, 0xcb, 0xfe, 0x72, 0x01, 0x26, - 0x53, 0x19, 0xf0, 0xc8, 0x87, 0x32, 0xf1, 0xd9, 0x09, 0x94, 0xfc, 0xa8, 0x47, 0x2d, 0x3e, 0xa5, - 0x26, 0xe2, 0x45, 0x41, 0x17, 0x2b, 0x0e, 0x8f, 0x84, 0x9b, 0xc5, 0xfe, 0xc3, 0x22, 0xcc, 0xf0, - 0x83, 0xb7, 0x9a, 0x8a, 0x67, 0x58, 0x93, 0xda, 0xc9, 0x5f, 0xd5, 0xd5, 0x26, 0xf8, 0x70, 0x6c, - 0x1f, 0xb5, 0x7c, 0x62, 0x6f, 0x46, 0x03, 0x79, 0xda, 0x7f, 0x3d, 0xe3, 0x69, 0x2f, 0xe4, 0x91, - 0x10, 0xd1, 0xb7, 0x47, 0x3f, 0x5a, 0xae, 0xf7, 0xbf, 0x53, 0x80, 0x13, 0x99, 0xda, 0x94, 0xe8, - 0x9d, 0x74, 0xf5, 0x29, 0x2b, 0x8f, 0xe3, 0x99, 0x7b, 0x56, 0x48, 0x1c, 0xae, 0x06, 0xd5, 0xc3, - 0x9a, 0xf0, 0x7f, 0x54, 0x80, 0xa9, 0x74, 0x51, 0xcd, 0x47, 0x70, 0xa4, 0x3e, 0x0a, 0x15, 0x56, - 0xaa, 0x8e, 0xdd, 0xca, 0xc1, 0x4f, 0x81, 0x78, 0x45, 0x35, 0xd9, 0x88, 0x35, 0xfc, 0x91, 0x28, - 0xed, 0x65, 0xff, 0x5d, 0x0b, 0xce, 0xf0, 0xb7, 0xcc, 0xce, 0xc3, 0xbf, 0xd6, 0x6b, 0x74, 0xdf, - 0xcc, 0xb7, 0x83, 0x99, 0x2a, 0x29, 0x87, 0x8d, 0x2f, 0xbb, 0x0d, 0x40, 0xf4, 0x36, 0x3d, 0x15, - 0x1e, 0xc1, 0xce, 0x0e, 0x35, 0x19, 0xec, 0x3f, 0x2a, 0x82, 0xbe, 0x00, 0x01, 0x79, 0x22, 0x6d, - 0x22, 0x97, 0x6a, 0x31, 0x9b, 0x9d, 0xc0, 0xd5, 0x57, 0x2d, 0x94, 0x33, 0x59, 0x13, 0xbf, 0x62, - 0xc1, 0xb8, 0x17, 0x78, 0x89, 0xe7, 0x30, 0xa5, 0x33, 0x9f, 0x8a, 0xf0, 0x8a, 0xdd, 0x0a, 0xa7, - 0x1c, 0x46, 0xe6, 0xd1, 0xa1, 0x62, 0x86, 0x4d, 0xce, 0xe8, 0x73, 0x22, 0x18, 0xae, 0x98, 0x5b, - 0xc2, 0x4f, 0x39, 0x13, 0x01, 0xd7, 0x82, 0x52, 0x44, 0x92, 0x48, 0xa6, 0x5a, 0x5d, 0x3d, 0x6a, - 0x84, 0x73, 0x12, 0x75, 0x54, 0x71, 0x30, 0x7d, 0x15, 0x15, 0x6d, 0xc6, 0x9c, 0x91, 0x1d, 0x03, - 0xea, 0x1e, 0x8b, 0x21, 0x03, 0x8d, 0xe6, 0xa1, 0xe2, 0xb4, 0x93, 0xb0, 0x49, 0x87, 0x49, 0x9c, - 0x6e, 0xea, 0x50, 0x2a, 0x09, 0xc0, 0x1a, 0xc7, 0x7e, 0xa7, 0x04, 0x99, 0x3c, 0x06, 0xb4, 0x6f, - 0x5e, 0xde, 0x61, 0xe5, 0x7b, 0x79, 0x87, 0xea, 0x4c, 0xaf, 0x0b, 0x3c, 0x50, 0x03, 0x4a, 0xad, - 0x1d, 0x27, 0x96, 0x3a, 0xe5, 0x6b, 0x72, 0x98, 0x36, 0x68, 0xe3, 0xdd, 0x83, 0xd9, 0x9f, 0x19, - 0xec, 0x8c, 0x82, 0xce, 0xd5, 0x79, 0x9e, 0x2f, 0xac, 0x59, 0x33, 0x1a, 0x98, 0xd3, 0x1f, 0xa6, - 0x26, 0xfe, 0x97, 0x44, 0x3d, 0x43, 0x4c, 0xe2, 0xb6, 0x9f, 0x88, 0xd9, 0xf0, 0x5a, 0x8e, 0xab, - 0x8c, 0x13, 0xd6, 0x19, 0x78, 0xfc, 0x3f, 0x36, 0x98, 0xa2, 0x37, 0xa0, 0x12, 0x27, 0x4e, 0x94, - 0xdc, 0x67, 0xce, 0x8c, 0x1a, 0xf4, 0x4d, 0x49, 0x04, 0x6b, 0x7a, 0xe8, 0x75, 0x56, 0x3c, 0xcb, - 0x8b, 0x77, 0xee, 0x33, 0x86, 0x55, 0x16, 0xda, 0x12, 0x14, 0xb0, 0x41, 0x8d, 0xaa, 0xec, 0x6c, - 0x6e, 0xf3, 0xc0, 0x8d, 0x32, 0xb3, 0xc9, 0x94, 0x28, 0xc4, 0x0a, 0x82, 0x0d, 0x2c, 0xfb, 0x0b, - 0x70, 0x2a, 0x7b, 0xdb, 0x97, 0x38, 0xb6, 0x6c, 0x44, 0x61, 0xbb, 0x95, 0xb5, 0x49, 0xd8, 0x6d, - 0x50, 0x98, 0xc3, 0xa8, 0x4d, 0xb2, 0xeb, 0x05, 0xb5, 0xac, 0x4d, 0x72, 0xd5, 0x0b, 0x6a, 0x98, - 0x41, 0x06, 0xb8, 0xd5, 0xe4, 0x9f, 0x5a, 0x70, 0xfe, 0xb0, 0x4b, 0xc9, 0xd0, 0x53, 0x30, 0x72, - 0xdb, 0x89, 0x64, 0x31, 0x3e, 0x26, 0x3b, 0x6e, 0x3a, 0x51, 0x80, 0x59, 0x2b, 0xea, 0xc0, 0x28, - 0xcf, 0x51, 0x14, 0x0a, 0xec, 0x6b, 0xf9, 0x5e, 0x91, 0x76, 0x95, 0x18, 0x1a, 0x34, 0xcf, 0x8f, - 0xc4, 0x82, 0xa1, 0xfd, 0xbe, 0x05, 0x68, 0x7d, 0x8f, 0x44, 0x91, 0x57, 0x33, 0xb2, 0x2a, 0xd1, - 0x4b, 0x30, 0x71, 0x6b, 0x73, 0xfd, 0xda, 0x46, 0xe8, 0x05, 0x2c, 0xc7, 0xda, 0xc8, 0x4b, 0xb9, - 0x62, 0xb4, 0xe3, 0x14, 0x16, 0x5a, 0x84, 0xe9, 0x5b, 0x6f, 0x51, 0x3b, 0xca, 0xac, 0x63, 0x5b, - 0xd0, 0x27, 0x67, 0x57, 0x5e, 0xcb, 0x00, 0x71, 0x37, 0x3e, 0x5a, 0x87, 0x33, 0x4d, 0xae, 0x81, - 0x33, 0xf3, 0x31, 0xe6, 0xea, 0x78, 0x24, 0x0b, 0x2f, 0x3c, 0x71, 0xe7, 0x60, 0xf6, 0xcc, 0x5a, - 0x2f, 0x04, 0xdc, 0xfb, 0x39, 0xfb, 0xbb, 0x05, 0x18, 0x37, 0x2e, 0xf6, 0x1b, 0xc0, 0x50, 0xce, - 0xdc, 0x45, 0x58, 0x18, 0xf0, 0x2e, 0xc2, 0xe7, 0xa0, 0xdc, 0x0a, 0x7d, 0xcf, 0xf5, 0x54, 0x95, - 0x08, 0x56, 0xcc, 0x6c, 0x43, 0xb4, 0x61, 0x05, 0x45, 0xb7, 0xa1, 0xa2, 0x2e, 0xbb, 0x12, 0xc9, - 0x7d, 0x79, 0x1d, 0x15, 0xa8, 0xc5, 0xab, 0x2f, 0xb1, 0xd2, 0xbc, 0x90, 0x0d, 0xa3, 0x6c, 0xe6, - 0xcb, 0x90, 0x26, 0x96, 0x75, 0xc1, 0x96, 0x44, 0x8c, 0x05, 0xc4, 0xfe, 0xa5, 0x31, 0x38, 0xdd, - 0xab, 0x00, 0x17, 0xfa, 0x3c, 0x8c, 0xf2, 0x3e, 0xe6, 0x53, 0xe3, 0xb1, 0x17, 0x8f, 0x65, 0x46, - 0x50, 0x74, 0x8b, 0xfd, 0xc6, 0x82, 0xa7, 0xe0, 0xee, 0x3b, 0xdb, 0x42, 0x8d, 0x38, 0x1e, 0xee, - 0xab, 0x8e, 0xe6, 0xbe, 0xea, 0x70, 0xee, 0xbe, 0xb3, 0x8d, 0xf6, 0xa1, 0xd4, 0xf0, 0x12, 0xe2, - 0x08, 0x65, 0xfa, 0xe6, 0xb1, 0x30, 0x27, 0x0e, 0x8f, 0x9c, 0x67, 0x3f, 0x31, 0x67, 0x88, 0xbe, - 0x63, 0xc1, 0x89, 0xed, 0x74, 0x12, 0x8b, 0xd8, 0x55, 0x9c, 0x63, 0x28, 0xb2, 0x96, 0x66, 0x54, - 0x3d, 0x75, 0xe7, 0x60, 0xf6, 0x44, 0xa6, 0x11, 0x67, 0xbb, 0x83, 0x7e, 0xd1, 0x82, 0xb1, 0xba, - 0xe7, 0x1b, 0x15, 0x84, 0x8e, 0xe1, 0xe3, 0x5c, 0x62, 0x0c, 0xf4, 0xce, 0xcb, 0xff, 0xc7, 0x58, - 0x72, 0xee, 0xe7, 0xce, 0x1b, 0x3d, 0xaa, 0x3b, 0x6f, 0xec, 0x21, 0x99, 0x4f, 0x7f, 0xbd, 0x00, - 0xcf, 0x0c, 0xf0, 0x8d, 0xcc, 0xa4, 0x08, 0xeb, 0x90, 0xa4, 0x88, 0xf3, 0x30, 0x12, 0x91, 0x56, - 0x98, 0xdd, 0xef, 0x58, 0xe4, 0x10, 0x83, 0xa0, 0xa7, 0xa1, 0xe8, 0xb4, 0x3c, 0xb1, 0xdd, 0x29, - 0x6f, 0xff, 0xc2, 0xc6, 0x0a, 0xa6, 0xed, 0xf4, 0x4b, 0x57, 0xb6, 0x65, 0x6a, 0x55, 0x3e, 0xc5, - 0x9a, 0xfb, 0x65, 0x6a, 0x71, 0x83, 0x46, 0x41, 0xb1, 0xe6, 0x6b, 0xaf, 0xc3, 0xd9, 0xfe, 0x33, - 0x04, 0xbd, 0x08, 0xe3, 0xdb, 0x91, 0x13, 0xb8, 0x3b, 0xac, 0xb0, 0xb9, 0x1c, 0x13, 0x16, 0x0a, - 0xaf, 0x9b, 0xb1, 0x89, 0x63, 0xff, 0x61, 0xa1, 0x37, 0x45, 0x2e, 0x04, 0x86, 0x19, 0x61, 0x31, - 0x7e, 0x85, 0x3e, 0xe3, 0xf7, 0x16, 0x94, 0x13, 0x16, 0x89, 0x4f, 0xea, 0x42, 0x92, 0xe4, 0x96, - 0x4c, 0xc6, 0xf6, 0x9a, 0x2d, 0x41, 0x1c, 0x2b, 0x36, 0x54, 0xe4, 0xfb, 0xba, 0xf8, 0x90, 0x10, - 0xf9, 0x99, 0x73, 0xb4, 0x25, 0x38, 0x69, 0xd4, 0x52, 0xe4, 0x81, 0xc8, 0xdc, 0x8d, 0xaa, 0xb2, - 0x73, 0x36, 0x32, 0x70, 0xdc, 0xf5, 0x84, 0xfd, 0x9b, 0x05, 0x78, 0xa2, 0xaf, 0x64, 0xd3, 0xbe, - 0x5e, 0xeb, 0x1e, 0xbe, 0xde, 0x23, 0x4f, 0x50, 0x73, 0x80, 0x47, 0x1e, 0xcc, 0x00, 0x3f, 0x0f, - 0x65, 0x2f, 0x88, 0x89, 0xdb, 0x8e, 0xf8, 0xa0, 0x19, 0x61, 0x79, 0x2b, 0xa2, 0x1d, 0x2b, 0x0c, - 0xfb, 0x8f, 0xfb, 0x4f, 0x35, 0xba, 0xcb, 0xfd, 0xd8, 0x8e, 0xd2, 0x2b, 0x30, 0xe9, 0xb4, 0x5a, - 0x1c, 0x8f, 0xf9, 0xd5, 0x32, 0xf9, 0x76, 0x0b, 0x26, 0x10, 0xa7, 0x71, 0x8d, 0x39, 0x3c, 0xda, - 0x6f, 0x0e, 0xdb, 0x7f, 0x66, 0x41, 0x05, 0x93, 0x3a, 0xaf, 0xc1, 0x89, 0x6e, 0x89, 0x21, 0xb2, - 0xf2, 0x28, 0x0e, 0xc1, 0xae, 0xcc, 0xf6, 0x58, 0xd1, 0x84, 0x5e, 0x83, 0xdd, 0x5d, 0x17, 0xb4, - 0x30, 0x54, 0x5d, 0x50, 0x55, 0x19, 0xb2, 0xd8, 0xbf, 0x32, 0xa4, 0xfd, 0xc3, 0x51, 0xfa, 0x7a, - 0xad, 0x70, 0x31, 0x22, 0xb5, 0x98, 0x7e, 0xdf, 0x76, 0xe4, 0x67, 0x6f, 0x12, 0xbc, 0x8e, 0x57, - 0x31, 0x6d, 0x4f, 0x1d, 0x02, 0x14, 0x86, 0xca, 0x36, 0x2a, 0x1e, 0x9a, 0x6d, 0xf4, 0x0a, 0x4c, - 0xc6, 0xf1, 0xce, 0x46, 0xe4, 0xed, 0x39, 0x09, 0x35, 0x2d, 0x44, 0x58, 0x86, 0xce, 0x10, 0xd8, - 0xbc, 0xac, 0x81, 0x38, 0x8d, 0x8b, 0x96, 0x61, 0x5a, 0xe7, 0xfc, 0x90, 0x28, 0x61, 0x51, 0x18, - 0x7c, 0x26, 0xa8, 0x00, 0x7d, 0x9d, 0x25, 0x24, 0x10, 0x70, 0xf7, 0x33, 0x54, 0x62, 0xa5, 0x1a, - 0x69, 0x47, 0x46, 0xd3, 0x12, 0x2b, 0x45, 0x87, 0xf6, 0xa5, 0xeb, 0x09, 0xb4, 0x06, 0xa7, 0xf8, - 0xc4, 0x60, 0x57, 0xd7, 0xaa, 0x37, 0xe2, 0x51, 0x33, 0x4f, 0x0a, 0x42, 0xa7, 0x96, 0xbb, 0x51, - 0x70, 0xaf, 0xe7, 0xa8, 0xdd, 0xa0, 0x9a, 0x57, 0x96, 0x84, 0xfd, 0xaa, 0xec, 0x06, 0x45, 0x66, - 0xa5, 0x86, 0x4d, 0x3c, 0xf4, 0x69, 0x78, 0x5c, 0xff, 0xe5, 0xf1, 0x6e, 0xfc, 0x50, 0x67, 0x49, - 0xa4, 0x53, 0xaa, 0x3a, 0x84, 0xcb, 0x3d, 0xd1, 0x6a, 0xb8, 0xdf, 0xf3, 0x68, 0x1b, 0xce, 0x2a, - 0xd0, 0x45, 0x6a, 0xa4, 0xb5, 0x22, 0x2f, 0x26, 0x55, 0x27, 0x26, 0xd7, 0x23, 0x9f, 0x25, 0x60, - 0x56, 0x74, 0x41, 0xf5, 0x65, 0x2f, 0xb9, 0xdc, 0x0b, 0x13, 0xaf, 0xe2, 0x7b, 0x50, 0x41, 0xf3, - 0x50, 0x21, 0x81, 0xb3, 0xed, 0x93, 0xf5, 0xc5, 0x15, 0x96, 0x96, 0x69, 0x9c, 0x21, 0x5d, 0x94, - 0x00, 0xac, 0x71, 0x94, 0x27, 0x70, 0xa2, 0x6f, 0x01, 0xfe, 0x0d, 0x38, 0xdd, 0x70, 0x5b, 0x54, - 0x0f, 0xf0, 0x5c, 0xb2, 0xe0, 0xba, 0xd4, 0xd0, 0xa7, 0x1f, 0x86, 0xd7, 0x45, 0x55, 0x6e, 0xee, - 0xe5, 0xc5, 0x8d, 0x2e, 0x1c, 0xdc, 0xf3, 0x49, 0xba, 0xc6, 0x5a, 0x51, 0xb8, 0xdf, 0x99, 0x39, - 0x95, 0x5e, 0x63, 0x1b, 0xb4, 0x11, 0x73, 0x98, 0xfd, 0xa7, 0x16, 0x4c, 0xaa, 0x35, 0xf6, 0x00, - 0x22, 0x7d, 0xfc, 0x74, 0xa4, 0xcf, 0xf2, 0xd1, 0xa5, 0x14, 0xeb, 0x79, 0x1f, 0x77, 0xf1, 0xef, - 0x03, 0x80, 0x96, 0x64, 0x6a, 0x13, 0xb1, 0xfa, 0x6e, 0x22, 0x8f, 0xac, 0x14, 0xe9, 0x95, 0x37, - 0x55, 0x7a, 0xb8, 0x79, 0x53, 0x9b, 0x70, 0x46, 0x6e, 0xf1, 0xfc, 0x18, 0xe5, 0x72, 0x18, 0x2b, - 0xa1, 0x54, 0xae, 0x3e, 0x2d, 0x08, 0x9d, 0x59, 0xe9, 0x85, 0x84, 0x7b, 0x3f, 0x9b, 0xd2, 0x2c, - 0xc6, 0x0e, 0xd3, 0x2c, 0xf4, 0x3a, 0x5c, 0xad, 0xcb, 0x4a, 0x84, 0x99, 0x75, 0xb8, 0x7a, 0x69, - 0x13, 0x6b, 0x9c, 0xde, 0xc2, 0xb8, 0x92, 0x93, 0x30, 0x86, 0xa1, 0x85, 0xb1, 0x14, 0x0b, 0xe3, - 0x7d, 0xc5, 0x82, 0x3c, 0xb9, 0x99, 0xe8, 0x7b, 0x72, 0xf3, 0x2a, 0x4c, 0x79, 0xc1, 0x0e, 0x89, - 0xbc, 0x84, 0xd4, 0xd8, 0x5a, 0x10, 0x57, 0xaa, 0xab, 0xad, 0x78, 0x25, 0x05, 0xc5, 0x19, 0xec, - 0xb4, 0x2c, 0x9b, 0x1a, 0x40, 0x96, 0xf5, 0xd9, 0x41, 0x4e, 0xe4, 0xb3, 0x83, 0x9c, 0x3c, 0xfa, - 0x0e, 0x32, 0x7d, 0xac, 0x3b, 0x08, 0xca, 0x65, 0x07, 0x19, 0x44, 0x38, 0x9b, 0x46, 0xd8, 0xe9, - 0x43, 0x8c, 0xb0, 0x7e, 0xdb, 0xc7, 0x99, 0xfb, 0xdd, 0x3e, 0xec, 0xaf, 0x16, 0xe0, 0x8c, 0x96, - 0x9d, 0x74, 0xc6, 0x7a, 0x75, 0x2a, 0x3d, 0x58, 0x01, 0x5a, 0x1e, 0xf6, 0x61, 0x04, 0x8b, 0xe9, - 0xb8, 0x33, 0x05, 0xc1, 0x06, 0x16, 0x8b, 0xb9, 0x22, 0x11, 0x2b, 0xe5, 0x92, 0x15, 0xac, 0x8b, - 0xa2, 0x1d, 0x2b, 0x0c, 0x3a, 0x27, 0xe8, 0x6f, 0x11, 0xc7, 0x9a, 0x4d, 0xef, 0x5e, 0xd4, 0x20, - 0x6c, 0xe2, 0xa1, 0xe7, 0x38, 0x13, 0xb6, 0xa8, 0xa9, 0x70, 0x9d, 0x10, 0x57, 0x2b, 0xc8, 0x75, - 0xac, 0xa0, 0xb2, 0x3b, 0x2c, 0xb8, 0xae, 0xd4, 0xdd, 0x1d, 0xe6, 0xe4, 0x52, 0x18, 0xf6, 0xff, - 0xb2, 0xe0, 0x89, 0x9e, 0x43, 0xf1, 0x00, 0x36, 0xcc, 0xfd, 0xf4, 0x86, 0xb9, 0x99, 0x97, 0x5a, - 0x6f, 0xbc, 0x45, 0x9f, 0xcd, 0xf3, 0xdf, 0x59, 0x30, 0xa5, 0xf1, 0x1f, 0xc0, 0xab, 0x7a, 0xe9, - 0x57, 0xcd, 0xcf, 0x82, 0xa9, 0x74, 0xbd, 0xdb, 0x9f, 0xb2, 0x77, 0xe3, 0xbe, 0x82, 0x05, 0x57, - 0xde, 0x80, 0x7f, 0xc8, 0x19, 0x79, 0x07, 0x46, 0x59, 0xf5, 0xd3, 0x38, 0x1f, 0x9f, 0x45, 0x9a, - 0x3f, 0x8b, 0x9a, 0xd5, 0x3e, 0x0b, 0xf6, 0x37, 0xc6, 0x82, 0x21, 0x2b, 0x34, 0xe4, 0xc5, 0x54, - 0x02, 0xd7, 0x44, 0x98, 0x9a, 0x2e, 0x34, 0x24, 0xda, 0xb1, 0xc2, 0xb0, 0x9b, 0x30, 0x93, 0x26, - 0xbe, 0x44, 0xea, 0xcc, 0x35, 0x3c, 0xd0, 0x6b, 0xce, 0x43, 0xc5, 0x61, 0x4f, 0xad, 0xb6, 0x9d, - 0xec, 0x6d, 0x3c, 0x0b, 0x12, 0x80, 0x35, 0x8e, 0xfd, 0xbb, 0x16, 0x9c, 0xea, 0xf1, 0x32, 0x39, - 0x86, 0xe7, 0x25, 0x5a, 0x0a, 0xf4, 0xda, 0x24, 0x3f, 0x02, 0x63, 0x35, 0x52, 0x77, 0xa4, 0xf3, - 0xd1, 0x90, 0x93, 0x4b, 0xbc, 0x19, 0x4b, 0xb8, 0xfd, 0xdf, 0x2c, 0x38, 0x91, 0xee, 0x6b, 0x8c, - 0xae, 0x00, 0xe2, 0x2f, 0xb3, 0xe4, 0xc5, 0x6e, 0xb8, 0x47, 0xa2, 0x0e, 0x7d, 0x73, 0xde, 0xeb, - 0xb3, 0x82, 0x12, 0x5a, 0xe8, 0xc2, 0xc0, 0x3d, 0x9e, 0x62, 0x85, 0x50, 0x6a, 0x6a, 0xb4, 0xe5, - 0x4c, 0xb9, 0x91, 0xe7, 0x4c, 0xd1, 0x1f, 0xd3, 0x74, 0xd0, 0x28, 0x96, 0xd8, 0xe4, 0x6f, 0xbf, - 0x3f, 0x02, 0x2a, 0x7e, 0x97, 0xb9, 0xb9, 0x72, 0x72, 0x12, 0xa6, 0xae, 0x6c, 0x2a, 0x0e, 0x70, - 0x65, 0x93, 0x9c, 0x0c, 0x23, 0xf7, 0x72, 0x41, 0xf1, 0x53, 0x02, 0xf3, 0x30, 0x4e, 0xbd, 0xe1, - 0x96, 0x06, 0x61, 0x13, 0x8f, 0xf6, 0xc4, 0xf7, 0xf6, 0x08, 0x7f, 0x68, 0x34, 0xdd, 0x93, 0x55, - 0x09, 0xc0, 0x1a, 0x87, 0xf6, 0xa4, 0xe6, 0xd5, 0xeb, 0xc2, 0xe4, 0x55, 0x3d, 0xa1, 0xa3, 0x83, - 0x19, 0x84, 0x62, 0xec, 0x84, 0xe1, 0xae, 0xd0, 0x28, 0x15, 0xc6, 0xe5, 0x30, 0xdc, 0xc5, 0x0c, - 0x42, 0x75, 0xa0, 0x20, 0x8c, 0x9a, 0xec, 0xb6, 0xa4, 0x9a, 0xe2, 0x22, 0x34, 0x49, 0xa5, 0x03, - 0x5d, 0xeb, 0x46, 0xc1, 0xbd, 0x9e, 0xa3, 0x33, 0xb0, 0x15, 0x91, 0x9a, 0xe7, 0x26, 0x26, 0x35, - 0x48, 0xcf, 0xc0, 0x8d, 0x2e, 0x0c, 0xdc, 0xe3, 0x29, 0xb4, 0x00, 0x27, 0x64, 0xfc, 0xb5, 0x4c, - 0x51, 0x1b, 0x4f, 0xa7, 0xc4, 0xe0, 0x34, 0x18, 0x67, 0xf1, 0xa9, 0xb4, 0x69, 0x8a, 0xec, 0x54, - 0xa6, 0x78, 0x1a, 0xd2, 0x46, 0x66, 0xad, 0x62, 0x85, 0x61, 0x7f, 0xa9, 0x48, 0x77, 0xc7, 0x3e, - 0x55, 0x6a, 0x1f, 0x98, 0x53, 0x3a, 0x3d, 0x23, 0x47, 0x06, 0x98, 0x91, 0x2f, 0xc1, 0xc4, 0xad, - 0x38, 0x0c, 0x94, 0xc3, 0xb7, 0xd4, 0xd7, 0xe1, 0x6b, 0x60, 0xf5, 0x76, 0xf8, 0x8e, 0xe6, 0xe5, - 0xf0, 0x1d, 0xbb, 0x4f, 0x87, 0xef, 0xf7, 0x4a, 0xa0, 0xea, 0x3c, 0x5e, 0x23, 0xc9, 0xed, 0x30, - 0xda, 0xf5, 0x82, 0x06, 0x8b, 0x5b, 0xff, 0x8e, 0x05, 0x13, 0x7c, 0xbd, 0xac, 0x9a, 0x31, 0xac, - 0xf5, 0x9c, 0xea, 0x11, 0xa6, 0x98, 0xcd, 0x6d, 0x19, 0x8c, 0x32, 0xc5, 0xf8, 0x4d, 0x10, 0x4e, - 0xf5, 0x08, 0xfd, 0x3c, 0x80, 0x3c, 0x1f, 0xac, 0x4b, 0x91, 0xb9, 0x92, 0x4f, 0xff, 0x30, 0xa9, - 0x6b, 0xdd, 0x74, 0x4b, 0x31, 0xc1, 0x06, 0x43, 0xf4, 0xd5, 0xec, 0x6d, 0x72, 0x9f, 0x3b, 0x96, - 0xb1, 0x19, 0x24, 0xba, 0x17, 0xc3, 0x98, 0x17, 0x34, 0xe8, 0x3c, 0x11, 0x3e, 0xf2, 0x0f, 0xf7, - 0xca, 0xf9, 0x58, 0x0d, 0x9d, 0x5a, 0xd5, 0xf1, 0x9d, 0xc0, 0x25, 0xd1, 0x0a, 0x47, 0x37, 0x6f, - 0x87, 0x61, 0x0d, 0x58, 0x12, 0xea, 0x2a, 0xb8, 0x59, 0x1a, 0xa4, 0xe0, 0xe6, 0xd9, 0x4f, 0xc2, - 0x74, 0xd7, 0xc7, 0x1c, 0x2a, 0x98, 0xf7, 0xfe, 0xe3, 0x80, 0xed, 0x7f, 0x36, 0xaa, 0x37, 0xad, - 0x6b, 0x61, 0x8d, 0x97, 0x7d, 0x8c, 0xf4, 0x17, 0x15, 0xba, 0x67, 0x8e, 0x53, 0xc4, 0xb8, 0x61, - 0x46, 0x35, 0x62, 0x93, 0x25, 0x9d, 0xa3, 0x2d, 0x27, 0x22, 0xc1, 0x71, 0xcf, 0xd1, 0x0d, 0xc5, - 0x04, 0x1b, 0x0c, 0xd1, 0x4e, 0x2a, 0x9a, 0xef, 0xd2, 0xd1, 0xa3, 0xf9, 0x58, 0x4a, 0x69, 0xaf, - 0xba, 0x76, 0xdf, 0xb2, 0x60, 0x2a, 0x48, 0xcd, 0x5c, 0xe1, 0x2f, 0xd9, 0x3a, 0x8e, 0x55, 0xc1, - 0xcb, 0x04, 0xa7, 0xdb, 0x70, 0x86, 0x7f, 0xaf, 0x2d, 0xad, 0x34, 0xe4, 0x96, 0xa6, 0xeb, 0xc7, - 0x8e, 0xf6, 0xab, 0x1f, 0x8b, 0x02, 0x55, 0xf1, 0x7a, 0x2c, 0xf7, 0x8a, 0xd7, 0xd0, 0xa3, 0xda, - 0xf5, 0x4d, 0xa8, 0xb8, 0x11, 0x71, 0x92, 0xfb, 0x2c, 0x7e, 0xcc, 0x9c, 0xc5, 0x8b, 0x92, 0x00, - 0xd6, 0xb4, 0xec, 0x7f, 0x5b, 0x84, 0x93, 0x72, 0x44, 0x64, 0xa4, 0x13, 0xdd, 0x1f, 0x39, 0x5f, - 0xad, 0xdc, 0xaa, 0xfd, 0xf1, 0xb2, 0x04, 0x60, 0x8d, 0x43, 0xf5, 0xb1, 0x76, 0x4c, 0xd6, 0x5b, - 0x24, 0x58, 0xf5, 0xb6, 0x63, 0xe1, 0xe7, 0x53, 0x0b, 0xe5, 0xba, 0x06, 0x61, 0x13, 0x8f, 0x2a, - 0xe3, 0x5c, 0x2f, 0x8e, 0xb3, 0x81, 0x83, 0x42, 0xdf, 0xc6, 0x12, 0x8e, 0x7e, 0xad, 0x67, 0xd9, - 0xfc, 0x7c, 0x42, 0x66, 0xbb, 0x02, 0xbc, 0x86, 0xac, 0x97, 0xff, 0x8e, 0x05, 0x27, 0x76, 0x53, - 0x39, 0x3f, 0x52, 0x24, 0x1f, 0x31, 0x3b, 0x35, 0x9d, 0x48, 0xa4, 0xa7, 0x70, 0xba, 0x3d, 0xc6, - 0x59, 0xee, 0xf6, 0xff, 0xb0, 0xc0, 0x14, 0x4f, 0x83, 0x69, 0x56, 0xc6, 0x3d, 0x37, 0x85, 0x43, - 0xee, 0xb9, 0x91, 0x4a, 0x58, 0x71, 0x30, 0xa5, 0x7f, 0x64, 0x08, 0xa5, 0xbf, 0xd4, 0x57, 0x6b, - 0x7b, 0x1a, 0x8a, 0x6d, 0xaf, 0x26, 0xf4, 0x76, 0xed, 0xd5, 0x5b, 0x59, 0xc2, 0xb4, 0xdd, 0xfe, - 0xfd, 0x92, 0xb6, 0xd3, 0x45, 0xa4, 0xe7, 0x8f, 0xc5, 0x6b, 0xd7, 0x55, 0xb2, 0x31, 0x7f, 0xf3, - 0x6b, 0x5d, 0xc9, 0xc6, 0x3f, 0x35, 0x7c, 0x20, 0x2f, 0x1f, 0xa0, 0x7e, 0xb9, 0xc6, 0x63, 0x87, - 0x44, 0xf1, 0xde, 0x82, 0x32, 0x35, 0x6d, 0xd8, 0x81, 0x5b, 0x39, 0xd5, 0xa9, 0xf2, 0x65, 0xd1, - 0x7e, 0xf7, 0x60, 0xf6, 0x27, 0x87, 0xef, 0x96, 0x7c, 0x1a, 0x2b, 0xfa, 0x28, 0x86, 0x0a, 0xfd, - 0xcd, 0x02, 0x8e, 0x85, 0xd1, 0x74, 0x5d, 0xc9, 0x22, 0x09, 0xc8, 0x25, 0x9a, 0x59, 0xf3, 0x41, - 0x01, 0x54, 0xd8, 0x95, 0x1d, 0x8c, 0x29, 0xb7, 0xad, 0x36, 0x54, 0xd8, 0xaf, 0x04, 0xdc, 0x3d, - 0x98, 0x7d, 0x65, 0x78, 0xa6, 0xea, 0x71, 0xac, 0x59, 0xd8, 0xef, 0x8e, 0xe8, 0xb9, 0x2b, 0x72, - 0xcc, 0x7f, 0x2c, 0xe6, 0xee, 0xcb, 0x99, 0xb9, 0x7b, 0xbe, 0x6b, 0xee, 0x4e, 0xe9, 0xab, 0x25, - 0x52, 0xb3, 0xf1, 0x41, 0x6f, 0xb0, 0x87, 0xdb, 0xf1, 0x4c, 0xb3, 0x78, 0xab, 0xed, 0x45, 0x24, - 0xde, 0x88, 0xda, 0x81, 0x17, 0x34, 0xc4, 0xdd, 0x75, 0x86, 0x66, 0x91, 0x02, 0xe3, 0x2c, 0x3e, - 0xbb, 0xf7, 0xae, 0x13, 0xb8, 0x37, 0x9d, 0x3d, 0x3e, 0xab, 0x8c, 0xb4, 0xdb, 0x4d, 0xd1, 0x8e, - 0x15, 0x86, 0xfd, 0x5d, 0xe6, 0x6f, 0x35, 0x32, 0x1d, 0xe8, 0x9c, 0xf0, 0xd9, 0x1d, 0x29, 0x3c, - 0x67, 0x57, 0xcd, 0x09, 0x7e, 0x31, 0x0a, 0x87, 0xa1, 0xdb, 0x30, 0xb6, 0xcd, 0x6b, 0x8e, 0xe7, - 0x53, 0xe4, 0x4b, 0x14, 0x30, 0x67, 0x75, 0x38, 0x65, 0x35, 0xf3, 0xbb, 0xfa, 0x27, 0x96, 0xdc, - 0xec, 0xf7, 0x46, 0xe0, 0x44, 0xe6, 0x16, 0x8d, 0x54, 0xc9, 0x91, 0xc2, 0xa1, 0x25, 0x47, 0x3e, - 0x03, 0x50, 0x23, 0x2d, 0x3f, 0xec, 0x30, 0x35, 0x67, 0x64, 0x68, 0x35, 0x47, 0x69, 0xc6, 0x4b, - 0x8a, 0x0a, 0x36, 0x28, 0x8a, 0x44, 0x65, 0x5e, 0xc1, 0x24, 0x93, 0xa8, 0x6c, 0xd4, 0xd9, 0x1b, - 0x7d, 0xb0, 0x75, 0xf6, 0x3c, 0x38, 0xc1, 0xbb, 0xa8, 0xf2, 0x09, 0xee, 0x23, 0x6d, 0x80, 0x45, - 0xa2, 0x2e, 0xa5, 0xc9, 0xe0, 0x2c, 0xdd, 0x87, 0x79, 0x49, 0x0e, 0xfa, 0x28, 0x54, 0xe4, 0x77, - 0x8e, 0x67, 0x2a, 0x3a, 0x27, 0x4b, 0x4e, 0x03, 0x76, 0x79, 0x8d, 0xf8, 0x69, 0x7f, 0xb3, 0x40, - 0xb5, 0x52, 0xfe, 0x4f, 0xe5, 0xd6, 0x3e, 0x0b, 0xa3, 0x4e, 0x3b, 0xd9, 0x09, 0xbb, 0xaa, 0xbc, - 0x2f, 0xb0, 0x56, 0x2c, 0xa0, 0x68, 0x15, 0x46, 0x6a, 0x3a, 0x5f, 0x72, 0x98, 0x51, 0xd4, 0x07, - 0x7c, 0x4e, 0x42, 0x30, 0xa3, 0x82, 0x9e, 0x82, 0x91, 0xc4, 0x69, 0xa4, 0xee, 0x5f, 0xdc, 0x72, - 0x1a, 0x31, 0x66, 0xad, 0xe6, 0xa6, 0x39, 0x72, 0xc8, 0xa6, 0xf9, 0x0a, 0x4c, 0xc6, 0x5e, 0x23, - 0x70, 0x92, 0x76, 0x44, 0x0c, 0x67, 0x92, 0xf6, 0xe9, 0x9b, 0x40, 0x9c, 0xc6, 0xb5, 0xdf, 0xaf, - 0xc0, 0xe9, 0x5e, 0xf7, 0x64, 0xe7, 0x1d, 0x75, 0xde, 0x8b, 0xc7, 0x83, 0x8b, 0x3a, 0xef, 0xc3, - 0xdd, 0x37, 0xa2, 0xce, 0x7d, 0x23, 0xea, 0xfc, 0xab, 0x16, 0x54, 0x54, 0xb0, 0xb5, 0x08, 0x18, - 0x7d, 0xe3, 0x18, 0xee, 0x22, 0x97, 0x2c, 0x44, 0xcc, 0xad, 0xfc, 0x8b, 0x35, 0xf3, 0xe3, 0x0b, - 0x43, 0xbf, 0x67, 0x87, 0x86, 0x0a, 0x43, 0x57, 0x31, 0xfa, 0xa5, 0x3c, 0x62, 0xf4, 0xfb, 0x7c, - 0xaa, 0x9e, 0x31, 0xfa, 0xdf, 0xb2, 0x60, 0xdc, 0x79, 0xbb, 0x1d, 0x91, 0x25, 0xb2, 0xb7, 0xde, - 0x8a, 0x85, 0x80, 0x7d, 0x33, 0xff, 0x0e, 0x2c, 0x68, 0x26, 0xa2, 0x1c, 0xad, 0x6e, 0xc0, 0x66, - 0x17, 0x52, 0x31, 0xf9, 0x63, 0x79, 0xc4, 0xe4, 0xf7, 0xea, 0xce, 0xa1, 0x31, 0xf9, 0xaf, 0xc0, - 0xa4, 0xeb, 0x87, 0x01, 0xd9, 0x88, 0xc2, 0x24, 0x74, 0x43, 0x5f, 0x28, 0xd3, 0x4a, 0x24, 0x2c, - 0x9a, 0x40, 0x9c, 0xc6, 0xed, 0x17, 0xd0, 0x5f, 0x39, 0x6a, 0x40, 0x3f, 0x3c, 0xa4, 0x80, 0xfe, - 0xbf, 0x28, 0xc0, 0xec, 0x21, 0x1f, 0x15, 0xbd, 0x0c, 0x13, 0x61, 0xd4, 0x70, 0x02, 0xef, 0x6d, - 0x9e, 0x4f, 0x59, 0x4a, 0x97, 0xbb, 0x58, 0x37, 0x60, 0x38, 0x85, 0x29, 0x43, 0x7e, 0x47, 0xfb, - 0x84, 0xfc, 0x7e, 0x1c, 0xc6, 0x13, 0xe2, 0x34, 0x45, 0xac, 0x84, 0x30, 0x80, 0xb4, 0x43, 0x49, - 0x83, 0xb0, 0x89, 0x47, 0xa7, 0xd1, 0x94, 0xe3, 0xba, 0x24, 0x8e, 0x65, 0x4c, 0xaf, 0x38, 0x9c, - 0xc9, 0x2d, 0x60, 0x98, 0x9d, 0x79, 0x2d, 0xa4, 0x58, 0xe0, 0x0c, 0x4b, 0xda, 0x79, 0xc7, 0xf7, - 0x79, 0xf8, 0x3e, 0x91, 0x37, 0x2a, 0xeb, 0xea, 0x0b, 0x1a, 0x84, 0x4d, 0x3c, 0xfb, 0xb7, 0x0a, - 0xf0, 0xf4, 0x3d, 0xc5, 0xcb, 0xc0, 0xe1, 0xd6, 0xed, 0x98, 0x44, 0x59, 0x87, 0xcc, 0xf5, 0x98, - 0x44, 0x98, 0x41, 0xf8, 0x28, 0xb5, 0x5a, 0xc6, 0x55, 0x2e, 0x79, 0x47, 0xf7, 0xf3, 0x51, 0x4a, - 0xb1, 0xc0, 0x19, 0x96, 0xd9, 0x51, 0x1a, 0x19, 0x70, 0x94, 0xfe, 0x5e, 0x01, 0x9e, 0x19, 0x40, - 0x08, 0xe7, 0x98, 0x05, 0x91, 0xce, 0x22, 0x29, 0x3e, 0x9c, 0x2c, 0x92, 0xfb, 0x1d, 0xae, 0xef, - 0x16, 0xe0, 0x6c, 0x7f, 0x59, 0x88, 0x7e, 0x9a, 0x1a, 0x51, 0x32, 0xd8, 0xc2, 0xcc, 0x40, 0x39, - 0xc5, 0x0d, 0xa8, 0x14, 0x08, 0x67, 0x71, 0xd1, 0x1c, 0x40, 0xcb, 0x49, 0x76, 0xe2, 0x8b, 0xfb, - 0x5e, 0x9c, 0x88, 0xdc, 0xc9, 0x29, 0x7e, 0x14, 0x2e, 0x5b, 0xb1, 0x81, 0x41, 0xd9, 0xb1, 0x7f, - 0x4b, 0xe1, 0xb5, 0x30, 0xe1, 0x0f, 0x71, 0x3d, 0xee, 0x94, 0xac, 0xf7, 0x67, 0x80, 0x70, 0x16, - 0x97, 0xb2, 0x63, 0xce, 0x16, 0xde, 0x51, 0x71, 0x5d, 0x3c, 0x65, 0xb7, 0xaa, 0x5a, 0xb1, 0x81, - 0x91, 0xcd, 0xad, 0x29, 0x0d, 0x90, 0x5b, 0xf3, 0x8f, 0x0a, 0xf0, 0x44, 0xdf, 0xbd, 0x74, 0xb0, - 0x05, 0xf8, 0xe8, 0x25, 0xd5, 0xdc, 0xdf, 0xdc, 0x19, 0x32, 0x55, 0xe4, 0xcf, 0xfa, 0xcc, 0x34, - 0x91, 0x2a, 0x92, 0xdd, 0x2a, 0xac, 0x61, 0xb7, 0x8a, 0x47, 0x68, 0x3c, 0xbb, 0xb2, 0x43, 0x46, - 0x86, 0xc8, 0x0e, 0xc9, 0x7c, 0x8c, 0xd2, 0x80, 0x0b, 0xf9, 0xfb, 0xfd, 0x87, 0x97, 0xea, 0xde, - 0x03, 0x1d, 0x4f, 0x2d, 0xc1, 0x49, 0x2f, 0x60, 0xb5, 0x5f, 0x37, 0xdb, 0xdb, 0x22, 0xb3, 0xb6, - 0x90, 0xbe, 0xd6, 0x68, 0x25, 0x03, 0xc7, 0x5d, 0x4f, 0x3c, 0x82, 0xd9, 0x3a, 0xf7, 0x39, 0xa4, - 0x9f, 0x81, 0x8a, 0xa2, 0xcd, 0x23, 0x23, 0xd5, 0x07, 0xed, 0x8a, 0x8c, 0x54, 0x5f, 0xd3, 0xc0, - 0xa2, 0x23, 0xb1, 0x4b, 0x3a, 0xd9, 0x99, 0x79, 0x95, 0x74, 0x98, 0x97, 0xd4, 0xfe, 0x18, 0x4c, - 0x28, 0x23, 0x72, 0xd0, 0xda, 0xa4, 0xf6, 0xbb, 0xa3, 0x30, 0x99, 0xaa, 0xa0, 0x90, 0x3a, 0xb3, - 0xb1, 0x0e, 0x3d, 0xb3, 0x61, 0xd1, 0xa9, 0xed, 0x40, 0x56, 0xff, 0x35, 0xa2, 0x53, 0xdb, 0x01, - 0xc1, 0x1c, 0x46, 0x4d, 0xf7, 0x5a, 0xd4, 0xc1, 0xed, 0x40, 0x44, 0xa4, 0x29, 0xd3, 0x7d, 0x89, - 0xb5, 0x62, 0x01, 0x45, 0x5f, 0xb4, 0x60, 0x22, 0x66, 0x07, 0x82, 0xfc, 0xc4, 0x4b, 0x7c, 0xd0, - 0x2b, 0x79, 0xdc, 0x5e, 0x2b, 0xaa, 0x85, 0x30, 0x67, 0xb6, 0xd9, 0x82, 0x53, 0x1c, 0xd1, 0x57, - 0x2c, 0xf3, 0xde, 0xde, 0xd1, 0x3c, 0x22, 0x29, 0xb3, 0x05, 0x2a, 0xf8, 0x51, 0xc9, 0xbd, 0xaf, - 0xef, 0xd5, 0xd7, 0x79, 0x8f, 0x3d, 0xb8, 0xeb, 0xbc, 0x3f, 0x0a, 0x95, 0xa6, 0x13, 0x78, 0x75, - 0x12, 0x27, 0xfc, 0x84, 0x48, 0xd6, 0xcd, 0x91, 0x8d, 0x58, 0xc3, 0xe9, 0x66, 0x17, 0xb3, 0x17, - 0x4b, 0x8c, 0x23, 0x1d, 0xb6, 0xd9, 0x6d, 0xea, 0x66, 0x6c, 0xe2, 0x98, 0xe7, 0x4f, 0xf0, 0x50, - 0xcf, 0x9f, 0xc6, 0x0f, 0x39, 0x7f, 0xfa, 0x07, 0x16, 0x9c, 0xe9, 0xf9, 0xd5, 0x1e, 0xdd, 0x18, - 0x25, 0xfb, 0xfd, 0x22, 0x9c, 0xea, 0x51, 0x0a, 0x05, 0x75, 0x8e, 0xed, 0x1e, 0x6a, 0x51, 0x6b, - 0x65, 0xb2, 0xef, 0x24, 0x1e, 0xee, 0xf4, 0x57, 0x9f, 0xc0, 0x16, 0x1f, 0xec, 0x09, 0xac, 0x31, - 0x2d, 0x47, 0x1e, 0xea, 0xb4, 0x2c, 0x1d, 0x32, 0x2d, 0xdf, 0x2f, 0x82, 0x71, 0xad, 0x3c, 0xfa, - 0x82, 0x59, 0x9e, 0xc8, 0xca, 0xab, 0x94, 0x0e, 0x27, 0xae, 0xca, 0x1b, 0xf1, 0xee, 0xf4, 0xaa, - 0x76, 0x94, 0x95, 0x00, 0x85, 0x01, 0x24, 0x80, 0x2f, 0xeb, 0x40, 0x15, 0xf3, 0xaf, 0x03, 0x55, - 0xc9, 0xd6, 0x80, 0x42, 0xbf, 0x67, 0xc1, 0x4c, 0xb3, 0x4f, 0xbd, 0xc2, 0x7c, 0xd2, 0xf3, 0xfb, - 0x55, 0x43, 0xac, 0x3e, 0x75, 0xe7, 0x60, 0xb6, 0x6f, 0x99, 0x48, 0xdc, 0xb7, 0x57, 0xf6, 0xdf, - 0xb4, 0xf8, 0x2a, 0xce, 0x7c, 0x05, 0xbd, 0xcd, 0x5a, 0xf7, 0xd8, 0x66, 0x9f, 0x67, 0x37, 0x9d, - 0xd5, 0x2f, 0x13, 0xc7, 0x17, 0xdb, 0xb1, 0x79, 0x69, 0x19, 0x6b, 0xc7, 0x0a, 0x83, 0xdd, 0x4d, - 0xe0, 0xfb, 0xe1, 0xed, 0x8b, 0xcd, 0x56, 0xd2, 0x11, 0x1b, 0xb3, 0xbe, 0x9b, 0x40, 0x41, 0xb0, - 0x81, 0x65, 0xff, 0x46, 0x81, 0xcf, 0x40, 0xe1, 0xa4, 0x7c, 0x39, 0x53, 0x08, 0x7b, 0x70, 0xff, - 0xde, 0xe7, 0x01, 0x5c, 0x75, 0xc9, 0x51, 0x3e, 0x97, 0xd4, 0xeb, 0x4b, 0x93, 0xcc, 0x9b, 0xd3, - 0x65, 0x1b, 0x36, 0xf8, 0xa5, 0x04, 0x53, 0xf1, 0x50, 0xc1, 0x94, 0x5a, 0xa3, 0x23, 0x87, 0xac, - 0xd1, 0xbf, 0xb0, 0x20, 0xa5, 0x5e, 0xa0, 0x16, 0x94, 0x68, 0x77, 0x3b, 0xf9, 0xdc, 0xdf, 0x64, - 0x92, 0xa6, 0x72, 0x46, 0x4c, 0x7b, 0xf6, 0x13, 0x73, 0x46, 0xc8, 0x17, 0xbe, 0xcc, 0x42, 0x1e, - 0x77, 0x8c, 0x99, 0x0c, 0x2f, 0x87, 0xe1, 0x2e, 0x77, 0x81, 0x68, 0xbf, 0xa8, 0xfd, 0x32, 0x4c, - 0x77, 0x75, 0x8a, 0xd5, 0xbc, 0x0d, 0xe5, 0xa5, 0x55, 0xc6, 0x74, 0x65, 0x15, 0xb8, 0x31, 0x87, - 0xd9, 0xdf, 0xb5, 0xe0, 0x64, 0x96, 0x3c, 0xfa, 0xb6, 0x05, 0xd3, 0x71, 0x96, 0xde, 0x71, 0x8d, - 0x9d, 0x8a, 0xf3, 0xe9, 0x02, 0xe1, 0xee, 0x4e, 0xd8, 0xff, 0x57, 0x4c, 0xfe, 0x9b, 0x5e, 0x50, - 0x0b, 0x6f, 0xab, 0x5d, 0xde, 0xea, 0xbb, 0xcb, 0xd3, 0xf5, 0xe8, 0xee, 0x90, 0x5a, 0xdb, 0xef, - 0xca, 0x64, 0xda, 0x14, 0xed, 0x58, 0x61, 0xa4, 0x6e, 0x88, 0x2e, 0x1e, 0x7a, 0x43, 0xf4, 0x4b, - 0x30, 0x61, 0x5e, 0xcc, 0x26, 0xe6, 0x25, 0xd3, 0x6e, 0xcd, 0x3b, 0xdc, 0x70, 0x0a, 0x2b, 0x73, - 0x35, 0x6f, 0xe9, 0xd0, 0xab, 0x79, 0x9f, 0x83, 0xb2, 0xb8, 0x66, 0x56, 0x46, 0xc3, 0xf1, 0x34, - 0x29, 0xd1, 0x86, 0x15, 0x94, 0x4a, 0x93, 0xa6, 0x13, 0xb4, 0x1d, 0x9f, 0x8e, 0x90, 0xc8, 0xc7, - 0x54, 0xcb, 0x70, 0x4d, 0x41, 0xb0, 0x81, 0x45, 0xdf, 0x38, 0xf1, 0x9a, 0xe4, 0xf5, 0x30, 0x90, - 0x71, 0x24, 0xfa, 0x80, 0x58, 0xb4, 0x63, 0x85, 0x61, 0xff, 0x17, 0x0b, 0xb2, 0x77, 0x64, 0xa6, - 0x8e, 0x0c, 0xac, 0x43, 0x73, 0x40, 0xd3, 0xd9, 0x68, 0x85, 0x81, 0xb2, 0xd1, 0xcc, 0x44, 0xb1, - 0xe2, 0x3d, 0x13, 0xc5, 0x7e, 0x42, 0xdf, 0x9c, 0xc0, 0x33, 0xca, 0xc6, 0x7b, 0xdd, 0x9a, 0x80, - 0x6c, 0x18, 0x75, 0x1d, 0x95, 0xd9, 0x3f, 0xc1, 0x15, 0xf1, 0xc5, 0x05, 0x86, 0x24, 0x20, 0xd5, - 0xed, 0xf7, 0x7e, 0x78, 0xee, 0x43, 0xdf, 0xff, 0xe1, 0xb9, 0x0f, 0xfd, 0xc9, 0x0f, 0xcf, 0x7d, - 0xe8, 0x8b, 0x77, 0xce, 0x59, 0xef, 0xdd, 0x39, 0x67, 0x7d, 0xff, 0xce, 0x39, 0xeb, 0x4f, 0xee, - 0x9c, 0xb3, 0xde, 0xbf, 0x73, 0xce, 0xfa, 0xd6, 0x7f, 0x3c, 0xf7, 0xa1, 0xd7, 0x7b, 0xc6, 0xfd, - 0xd0, 0x1f, 0x2f, 0xb8, 0xb5, 0xf9, 0xbd, 0x0b, 0x2c, 0xf4, 0x84, 0xae, 0x86, 0x79, 0x63, 0x0a, - 0xcc, 0xcb, 0xd5, 0xf0, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x38, 0xc0, 0xfa, 0xc5, 0xd3, 0xc1, - 0x00, 0x00, + // 11030 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x6d, 0x70, 0x1c, 0xc9, + 0x75, 0x98, 0x66, 0x17, 0x0b, 0xec, 0x3e, 0x7c, 0x90, 0x6c, 0x92, 0x77, 0x20, 0x75, 0x77, 0xa0, + 0xe7, 0xe2, 0xd3, 0x39, 0xba, 0x03, 0x7c, 0xf4, 0x9d, 0x7c, 0xf1, 0xd9, 0x92, 0xb1, 0x00, 0x09, + 0x82, 0x04, 0x08, 0x5c, 0x03, 0x24, 0xa5, 0x93, 0x4f, 0xa7, 0xc1, 0x6e, 0x63, 0x31, 0xc4, 0xec, + 0xcc, 0xdc, 0xcc, 0x2c, 0x08, 0x9c, 0x25, 0x59, 0xb2, 0x64, 0x5b, 0x89, 0x3e, 0x4e, 0x91, 0x92, + 0xf2, 0x39, 0xb1, 0x14, 0xd9, 0x72, 0x52, 0x71, 0x25, 0xaa, 0x38, 0xc9, 0x8f, 0x38, 0x71, 0x52, + 0x2e, 0xdb, 0xa9, 0x94, 0x52, 0x4a, 0xca, 0x2e, 0x97, 0xcb, 0x72, 0x12, 0x1b, 0x91, 0x98, 0x4a, + 0x25, 0x95, 0xaa, 0xb8, 0xca, 0x89, 0x7f, 0x24, 0x4c, 0x7e, 0xa4, 0xfa, 0xbb, 0x67, 0x76, 0x16, + 0x58, 0x00, 0x03, 0x92, 0x52, 0xee, 0xdf, 0x6e, 0xbf, 0x37, 0xef, 0xf5, 0xf4, 0x74, 0xbf, 0xf7, + 0xfa, 0xf5, 0x7b, 0xaf, 0x61, 0xa1, 0xe5, 0x26, 0x1b, 0x9d, 0xb5, 0xc9, 0x46, 0xd0, 0x9e, 0x72, + 0xa2, 0x56, 0x10, 0x46, 0xc1, 0x6d, 0xf6, 0xe3, 0xd9, 0x46, 0x73, 0x6a, 0xeb, 0xe2, 0x54, 0xb8, + 0xd9, 0x9a, 0x72, 0x42, 0x37, 0x9e, 0x72, 0xc2, 0xd0, 0x73, 0x1b, 0x4e, 0xe2, 0x06, 0xfe, 0xd4, + 0xd6, 0x73, 0x8e, 0x17, 0x6e, 0x38, 0xcf, 0x4d, 0xb5, 0x88, 0x4f, 0x22, 0x27, 0x21, 0xcd, 0xc9, + 0x30, 0x0a, 0x92, 0x00, 0xfd, 0xa8, 0xa6, 0x36, 0x29, 0xa9, 0xb1, 0x1f, 0xaf, 0x35, 0x9a, 0x93, + 0x5b, 0x17, 0x27, 0xc3, 0xcd, 0xd6, 0x24, 0xa5, 0x36, 0x69, 0x50, 0x9b, 0x94, 0xd4, 0xce, 0x3f, + 0x6b, 0xf4, 0xa5, 0x15, 0xb4, 0x82, 0x29, 0x46, 0x74, 0xad, 0xb3, 0xce, 0xfe, 0xb1, 0x3f, 0xec, + 0x17, 0x67, 0x76, 0xde, 0xde, 0x7c, 0x31, 0x9e, 0x74, 0x03, 0xda, 0xbd, 0xa9, 0x46, 0x10, 0x91, + 0xa9, 0xad, 0xae, 0x0e, 0x9d, 0xbf, 0xa2, 0x71, 0xc8, 0x76, 0x42, 0xfc, 0xd8, 0x0d, 0xfc, 0xf8, + 0x59, 0xda, 0x05, 0x12, 0x6d, 0x91, 0xc8, 0x7c, 0x3d, 0x03, 0x21, 0x8f, 0xd2, 0xf3, 0x9a, 0x52, + 0xdb, 0x69, 0x6c, 0xb8, 0x3e, 0x89, 0x76, 0xf4, 0xe3, 0x6d, 0x92, 0x38, 0x79, 0x4f, 0x4d, 0xf5, + 0x7a, 0x2a, 0xea, 0xf8, 0x89, 0xdb, 0x26, 0x5d, 0x0f, 0xbc, 0x67, 0xbf, 0x07, 0xe2, 0xc6, 0x06, + 0x69, 0x3b, 0x5d, 0xcf, 0xfd, 0x50, 0xaf, 0xe7, 0x3a, 0x89, 0xeb, 0x4d, 0xb9, 0x7e, 0x12, 0x27, + 0x51, 0xf6, 0x21, 0xfb, 0x17, 0x2d, 0x18, 0x9d, 0xbe, 0xb5, 0x32, 0xdd, 0x49, 0x36, 0x66, 0x02, + 0x7f, 0xdd, 0x6d, 0xa1, 0x17, 0x60, 0xb8, 0xe1, 0x75, 0xe2, 0x84, 0x44, 0xd7, 0x9d, 0x36, 0x19, + 0xb7, 0x2e, 0x58, 0x4f, 0xd7, 0xea, 0xa7, 0xbf, 0xb1, 0x3b, 0xf1, 0x8e, 0xbb, 0xbb, 0x13, 0xc3, + 0x33, 0x1a, 0x84, 0x4d, 0x3c, 0xf4, 0x03, 0x30, 0x14, 0x05, 0x1e, 0x99, 0xc6, 0xd7, 0xc7, 0x4b, + 0xec, 0x91, 0x13, 0xe2, 0x91, 0x21, 0xcc, 0x9b, 0xb1, 0x84, 0x53, 0xd4, 0x30, 0x0a, 0xd6, 0x5d, + 0x8f, 0x8c, 0x97, 0xd3, 0xa8, 0xcb, 0xbc, 0x19, 0x4b, 0xb8, 0xfd, 0x87, 0x25, 0x80, 0xe9, 0x30, + 0x5c, 0x8e, 0x82, 0xdb, 0xa4, 0x91, 0xa0, 0x0f, 0x43, 0x95, 0x0e, 0x73, 0xd3, 0x49, 0x1c, 0xd6, + 0xb1, 0xe1, 0x8b, 0x3f, 0x38, 0xc9, 0xdf, 0x7a, 0xd2, 0x7c, 0x6b, 0x3d, 0xc9, 0x28, 0xf6, 0xe4, + 0xd6, 0x73, 0x93, 0x4b, 0x6b, 0xf4, 0xf9, 0x45, 0x92, 0x38, 0x75, 0x24, 0x98, 0x81, 0x6e, 0xc3, + 0x8a, 0x2a, 0xf2, 0x61, 0x20, 0x0e, 0x49, 0x83, 0xbd, 0xc3, 0xf0, 0xc5, 0x85, 0xc9, 0xa3, 0xcc, + 0xe6, 0x49, 0xdd, 0xf3, 0x95, 0x90, 0x34, 0xea, 0x23, 0x82, 0xf3, 0x00, 0xfd, 0x87, 0x19, 0x1f, + 0xb4, 0x05, 0x83, 0x71, 0xe2, 0x24, 0x9d, 0x98, 0x0d, 0xc5, 0xf0, 0xc5, 0xeb, 0x85, 0x71, 0x64, + 0x54, 0xeb, 0x63, 0x82, 0xe7, 0x20, 0xff, 0x8f, 0x05, 0x37, 0xfb, 0x4f, 0x2c, 0x18, 0xd3, 0xc8, + 0x0b, 0x6e, 0x9c, 0xa0, 0x9f, 0xe8, 0x1a, 0xdc, 0xc9, 0xfe, 0x06, 0x97, 0x3e, 0xcd, 0x86, 0xf6, + 0xa4, 0x60, 0x56, 0x95, 0x2d, 0xc6, 0xc0, 0xb6, 0xa1, 0xe2, 0x26, 0xa4, 0x1d, 0x8f, 0x97, 0x2e, + 0x94, 0x9f, 0x1e, 0xbe, 0x78, 0xa5, 0xa8, 0xf7, 0xac, 0x8f, 0x0a, 0xa6, 0x95, 0x79, 0x4a, 0x1e, + 0x73, 0x2e, 0xf6, 0xaf, 0x8e, 0x98, 0xef, 0x47, 0x07, 0x1c, 0x3d, 0x07, 0xc3, 0x71, 0xd0, 0x89, + 0x1a, 0x04, 0x93, 0x30, 0x88, 0xc7, 0xad, 0x0b, 0x65, 0x3a, 0xf5, 0xe8, 0xa4, 0x5e, 0xd1, 0xcd, + 0xd8, 0xc4, 0x41, 0x9f, 0xb7, 0x60, 0xa4, 0x49, 0xe2, 0xc4, 0xf5, 0x19, 0x7f, 0xd9, 0xf9, 0xd5, + 0x23, 0x77, 0x5e, 0x36, 0xce, 0x6a, 0xe2, 0xf5, 0x33, 0xe2, 0x45, 0x46, 0x8c, 0xc6, 0x18, 0xa7, + 0xf8, 0xd3, 0xc5, 0xd9, 0x24, 0x71, 0x23, 0x72, 0x43, 0xfa, 0x5f, 0x2c, 0x1f, 0xb5, 0x38, 0x67, + 0x35, 0x08, 0x9b, 0x78, 0xc8, 0x87, 0x0a, 0x5d, 0x7c, 0xf1, 0xf8, 0x00, 0xeb, 0xff, 0xfc, 0xd1, + 0xfa, 0x2f, 0x06, 0x95, 0xae, 0x6b, 0x3d, 0xfa, 0xf4, 0x5f, 0x8c, 0x39, 0x1b, 0xf4, 0x39, 0x0b, + 0xc6, 0x85, 0x70, 0xc0, 0x84, 0x0f, 0xe8, 0xad, 0x0d, 0x37, 0x21, 0x9e, 0x1b, 0x27, 0xe3, 0x15, + 0xd6, 0x87, 0xa9, 0xfe, 0xe6, 0xd6, 0x5c, 0x14, 0x74, 0xc2, 0x6b, 0xae, 0xdf, 0xac, 0x5f, 0x10, + 0x9c, 0xc6, 0x67, 0x7a, 0x10, 0xc6, 0x3d, 0x59, 0xa2, 0x2f, 0x59, 0x70, 0xde, 0x77, 0xda, 0x24, + 0x0e, 0x1d, 0xfa, 0x69, 0x39, 0xb8, 0xee, 0x39, 0x8d, 0x4d, 0xd6, 0xa3, 0xc1, 0xc3, 0xf5, 0xc8, + 0x16, 0x3d, 0x3a, 0x7f, 0xbd, 0x27, 0x69, 0xbc, 0x07, 0x5b, 0xf4, 0x35, 0x0b, 0x4e, 0x05, 0x51, + 0xb8, 0xe1, 0xf8, 0xa4, 0x29, 0xa1, 0xf1, 0xf8, 0x10, 0x5b, 0x7a, 0x1f, 0x3a, 0xda, 0x27, 0x5a, + 0xca, 0x92, 0x5d, 0x0c, 0x7c, 0x37, 0x09, 0xa2, 0x15, 0x92, 0x24, 0xae, 0xdf, 0x8a, 0xeb, 0x67, + 0xef, 0xee, 0x4e, 0x9c, 0xea, 0xc2, 0xc2, 0xdd, 0xfd, 0x41, 0x3f, 0x09, 0xc3, 0xf1, 0x8e, 0xdf, + 0xb8, 0xe5, 0xfa, 0xcd, 0xe0, 0x4e, 0x3c, 0x5e, 0x2d, 0x62, 0xf9, 0xae, 0x28, 0x82, 0x62, 0x01, + 0x6a, 0x06, 0xd8, 0xe4, 0x96, 0xff, 0xe1, 0xf4, 0x54, 0xaa, 0x15, 0xfd, 0xe1, 0xf4, 0x64, 0xda, + 0x83, 0x2d, 0xfa, 0x39, 0x0b, 0x46, 0x63, 0xb7, 0xe5, 0x3b, 0x49, 0x27, 0x22, 0xd7, 0xc8, 0x4e, + 0x3c, 0x0e, 0xac, 0x23, 0x57, 0x8f, 0x38, 0x2a, 0x06, 0xc9, 0xfa, 0x59, 0xd1, 0xc7, 0x51, 0xb3, + 0x35, 0xc6, 0x69, 0xbe, 0x79, 0x0b, 0x4d, 0x4f, 0xeb, 0xe1, 0x62, 0x17, 0x9a, 0x9e, 0xd4, 0x3d, + 0x59, 0xa2, 0x1f, 0x87, 0x93, 0xbc, 0x49, 0x8d, 0x6c, 0x3c, 0x3e, 0xc2, 0x04, 0xed, 0x99, 0xbb, + 0xbb, 0x13, 0x27, 0x57, 0x32, 0x30, 0xdc, 0x85, 0x8d, 0x5e, 0x87, 0x89, 0x90, 0x44, 0x6d, 0x37, + 0x59, 0xf2, 0xbd, 0x1d, 0x29, 0xbe, 0x1b, 0x41, 0x48, 0x9a, 0xa2, 0x3b, 0xf1, 0xf8, 0xe8, 0x05, + 0xeb, 0xe9, 0x6a, 0xfd, 0x5d, 0xa2, 0x9b, 0x13, 0xcb, 0x7b, 0xa3, 0xe3, 0xfd, 0xe8, 0xd9, 0xff, + 0xba, 0x04, 0x27, 0xb3, 0x8a, 0x13, 0xfd, 0x1d, 0x0b, 0x4e, 0xdc, 0xbe, 0x93, 0xac, 0x06, 0x9b, + 0xc4, 0x8f, 0xeb, 0x3b, 0x54, 0xbc, 0x31, 0x95, 0x31, 0x7c, 0xb1, 0x51, 0xac, 0x8a, 0x9e, 0xbc, + 0x9a, 0xe6, 0x72, 0xc9, 0x4f, 0xa2, 0x9d, 0xfa, 0xa3, 0xe2, 0xed, 0x4e, 0x5c, 0xbd, 0xb5, 0x6a, + 0x42, 0x71, 0xb6, 0x53, 0xe7, 0x3f, 0x63, 0xc1, 0x99, 0x3c, 0x12, 0xe8, 0x24, 0x94, 0x37, 0xc9, + 0x0e, 0x37, 0xe0, 0x30, 0xfd, 0x89, 0x5e, 0x85, 0xca, 0x96, 0xe3, 0x75, 0x88, 0xb0, 0x6e, 0xe6, + 0x8e, 0xf6, 0x22, 0xaa, 0x67, 0x98, 0x53, 0xfd, 0x91, 0xd2, 0x8b, 0x96, 0xfd, 0xbb, 0x65, 0x18, + 0x36, 0xf4, 0xdb, 0x7d, 0xb0, 0xd8, 0x82, 0x94, 0xc5, 0xb6, 0x58, 0x98, 0x6a, 0xee, 0x69, 0xb2, + 0xdd, 0xc9, 0x98, 0x6c, 0x4b, 0xc5, 0xb1, 0xdc, 0xd3, 0x66, 0x43, 0x09, 0xd4, 0x82, 0x90, 0x5a, + 0xef, 0x54, 0xf5, 0x0f, 0x14, 0xf1, 0x09, 0x97, 0x24, 0xb9, 0xfa, 0xe8, 0xdd, 0xdd, 0x89, 0x9a, + 0xfa, 0x8b, 0x35, 0x23, 0xfb, 0x5b, 0x16, 0x9c, 0x31, 0xfa, 0x38, 0x13, 0xf8, 0x4d, 0x97, 0x7d, + 0xda, 0x0b, 0x30, 0x90, 0xec, 0x84, 0x72, 0x87, 0xa0, 0x46, 0x6a, 0x75, 0x27, 0x24, 0x98, 0x41, + 0xa8, 0xa1, 0xdf, 0x26, 0x71, 0xec, 0xb4, 0x48, 0x76, 0x4f, 0xb0, 0xc8, 0x9b, 0xb1, 0x84, 0xa3, + 0x08, 0x90, 0xe7, 0xc4, 0xc9, 0x6a, 0xe4, 0xf8, 0x31, 0x23, 0xbf, 0xea, 0xb6, 0x89, 0x18, 0xe0, + 0xbf, 0xd8, 0xdf, 0x8c, 0xa1, 0x4f, 0xd4, 0x1f, 0xb9, 0xbb, 0x3b, 0x81, 0x16, 0xba, 0x28, 0xe1, + 0x1c, 0xea, 0xf6, 0x97, 0x2c, 0x78, 0x24, 0xdf, 0x16, 0x43, 0x4f, 0xc1, 0x20, 0xdf, 0x1e, 0x8a, + 0xb7, 0xd3, 0x9f, 0x84, 0xb5, 0x62, 0x01, 0x45, 0x53, 0x50, 0x53, 0x7a, 0x42, 0xbc, 0xe3, 0x29, + 0x81, 0x5a, 0xd3, 0xca, 0x45, 0xe3, 0xd0, 0x41, 0xa3, 0x7f, 0x84, 0xe5, 0xa6, 0x06, 0x8d, 0xed, + 0xa7, 0x18, 0xc4, 0xfe, 0x8f, 0x16, 0x9c, 0x30, 0x7a, 0x75, 0x1f, 0x4c, 0x73, 0x3f, 0x6d, 0x9a, + 0xcf, 0x17, 0x36, 0x9f, 0x7b, 0xd8, 0xe6, 0x9f, 0xb3, 0xe0, 0xbc, 0x81, 0xb5, 0xe8, 0x24, 0x8d, + 0x8d, 0x4b, 0xdb, 0x61, 0x44, 0x62, 0xba, 0xf5, 0x46, 0x8f, 0x1b, 0x72, 0xab, 0x3e, 0x2c, 0x28, + 0x94, 0xaf, 0x91, 0x1d, 0x2e, 0xc4, 0x9e, 0x81, 0x2a, 0x9f, 0x9c, 0x41, 0x24, 0x46, 0x5c, 0xbd, + 0xdb, 0x92, 0x68, 0xc7, 0x0a, 0x03, 0xd9, 0x30, 0xc8, 0x84, 0x13, 0x5d, 0xac, 0x54, 0x0d, 0x01, + 0xfd, 0x88, 0x37, 0x59, 0x0b, 0x16, 0x10, 0x3b, 0x4e, 0x75, 0x67, 0x39, 0x22, 0xec, 0xe3, 0x36, + 0x2f, 0xbb, 0xc4, 0x6b, 0xc6, 0x74, 0xdb, 0xe0, 0xf8, 0x7e, 0x90, 0x88, 0x1d, 0x80, 0xb1, 0x6d, + 0x98, 0xd6, 0xcd, 0xd8, 0xc4, 0xa1, 0x4c, 0x3d, 0x67, 0x8d, 0x78, 0x7c, 0x44, 0x05, 0xd3, 0x05, + 0xd6, 0x82, 0x05, 0xc4, 0xbe, 0x5b, 0x62, 0x1b, 0x14, 0xb5, 0xf4, 0xc9, 0xfd, 0xd8, 0xdd, 0x46, + 0x29, 0x59, 0xb9, 0x5c, 0x9c, 0xe0, 0x22, 0xbd, 0x77, 0xb8, 0x6f, 0x64, 0xc4, 0x25, 0x2e, 0x94, + 0xeb, 0xde, 0xbb, 0xdc, 0xdf, 0x2a, 0xc1, 0x44, 0xfa, 0x81, 0x2e, 0x69, 0x4b, 0xb7, 0x54, 0x06, + 0xa3, 0xac, 0xbf, 0xc3, 0xc0, 0xc7, 0x26, 0x5e, 0x0f, 0x81, 0x55, 0x3a, 0x4e, 0x81, 0x65, 0xca, + 0xd3, 0xf2, 0x3e, 0xf2, 0xf4, 0x29, 0x35, 0xea, 0x03, 0x19, 0x01, 0x96, 0xd6, 0x29, 0x17, 0x60, + 0x20, 0x4e, 0x48, 0x38, 0x5e, 0x49, 0xcb, 0xa3, 0x95, 0x84, 0x84, 0x98, 0x41, 0xec, 0xff, 0x56, + 0x82, 0x47, 0xd3, 0x63, 0xa8, 0x55, 0xc0, 0xfb, 0x52, 0x2a, 0xe0, 0xdd, 0xa6, 0x0a, 0xb8, 0xb7, + 0x3b, 0xf1, 0xce, 0x1e, 0x8f, 0x7d, 0xd7, 0x68, 0x08, 0x34, 0x97, 0x19, 0xc5, 0xa9, 0xf4, 0x28, + 0xde, 0xdb, 0x9d, 0x78, 0xbc, 0xc7, 0x3b, 0x66, 0x86, 0xf9, 0x29, 0x18, 0x8c, 0x88, 0x13, 0x07, + 0xbe, 0x18, 0x68, 0xf5, 0x39, 0x30, 0x6b, 0xc5, 0x02, 0x6a, 0xff, 0x7e, 0x2d, 0x3b, 0xd8, 0x73, + 0xdc, 0x61, 0x17, 0x44, 0xc8, 0x85, 0x01, 0x66, 0xd6, 0x73, 0xd1, 0x70, 0xed, 0x68, 0xcb, 0x88, + 0xaa, 0x01, 0x45, 0xba, 0x5e, 0xa5, 0x5f, 0x8d, 0x36, 0x61, 0xc6, 0x02, 0x6d, 0x43, 0xb5, 0x21, + 0xad, 0xed, 0x52, 0x11, 0x7e, 0x29, 0x61, 0x6b, 0x6b, 0x8e, 0x23, 0x54, 0x5e, 0x2b, 0x13, 0x5d, + 0x71, 0x43, 0x04, 0xca, 0x2d, 0x37, 0x11, 0x9f, 0xf5, 0x88, 0xfb, 0xa9, 0x39, 0xd7, 0x78, 0xc5, + 0x21, 0xaa, 0x44, 0xe6, 0xdc, 0x04, 0x53, 0xfa, 0xe8, 0x67, 0x2c, 0x18, 0x8e, 0x1b, 0xed, 0xe5, + 0x28, 0xd8, 0x72, 0x9b, 0x24, 0x12, 0xd6, 0xd4, 0x11, 0x45, 0xd3, 0xca, 0xcc, 0xa2, 0x24, 0xa8, + 0xf9, 0xf2, 0xfd, 0xad, 0x86, 0x60, 0x93, 0x2f, 0xdd, 0x65, 0x3c, 0x2a, 0xde, 0x7d, 0x96, 0x34, + 0x5c, 0xaa, 0xff, 0xe4, 0xa6, 0x8a, 0xcd, 0x94, 0x23, 0x5b, 0x97, 0xb3, 0x9d, 0xc6, 0x26, 0x5d, + 0x6f, 0xba, 0x43, 0xef, 0xbc, 0xbb, 0x3b, 0xf1, 0xe8, 0x4c, 0x3e, 0x4f, 0xdc, 0xab, 0x33, 0x6c, + 0xc0, 0xc2, 0x8e, 0xe7, 0x61, 0xf2, 0x7a, 0x87, 0x30, 0x97, 0x49, 0x01, 0x03, 0xb6, 0xac, 0x09, + 0x66, 0x06, 0xcc, 0x80, 0x60, 0x93, 0x2f, 0x7a, 0x1d, 0x06, 0xdb, 0x4e, 0x12, 0xb9, 0xdb, 0xc2, + 0x4f, 0x72, 0x44, 0x7b, 0x7f, 0x91, 0xd1, 0xd2, 0xcc, 0x99, 0xa6, 0xe6, 0x8d, 0x58, 0x30, 0x42, + 0x6d, 0xa8, 0xb4, 0x49, 0xd4, 0x22, 0xe3, 0xd5, 0x22, 0x7c, 0xc2, 0x8b, 0x94, 0x94, 0x66, 0x58, + 0xa3, 0xd6, 0x11, 0x6b, 0xc3, 0x9c, 0x0b, 0x7a, 0x15, 0xaa, 0x31, 0xf1, 0x48, 0x83, 0xda, 0x37, + 0x35, 0xc6, 0xf1, 0x87, 0xfa, 0xb4, 0xf5, 0xa8, 0x61, 0xb1, 0x22, 0x1e, 0xe5, 0x0b, 0x4c, 0xfe, + 0xc3, 0x8a, 0x24, 0x1d, 0xc0, 0xd0, 0xeb, 0xb4, 0x5c, 0x7f, 0x1c, 0x8a, 0x18, 0xc0, 0x65, 0x46, + 0x2b, 0x33, 0x80, 0xbc, 0x11, 0x0b, 0x46, 0xf6, 0x7f, 0xb6, 0x00, 0xa5, 0x85, 0xda, 0x7d, 0x30, + 0x6a, 0x5f, 0x4f, 0x1b, 0xb5, 0x0b, 0x45, 0x5a, 0x1d, 0x3d, 0xec, 0xda, 0xdf, 0xa8, 0x41, 0x46, + 0x1d, 0x5c, 0x27, 0x71, 0x42, 0x9a, 0x6f, 0x8b, 0xf0, 0xb7, 0x45, 0xf8, 0xdb, 0x22, 0x5c, 0x89, + 0xf0, 0xb5, 0x8c, 0x08, 0x7f, 0xaf, 0xb1, 0xea, 0xf5, 0x01, 0xec, 0x6b, 0xea, 0x84, 0xd6, 0xec, + 0x81, 0x81, 0x40, 0x25, 0xc1, 0xd5, 0x95, 0xa5, 0xeb, 0xb9, 0x32, 0xfb, 0xb5, 0xb4, 0xcc, 0x3e, + 0x2a, 0x8b, 0xff, 0x1f, 0xa4, 0xf4, 0xbf, 0xb2, 0xe0, 0x5d, 0x69, 0xe9, 0x25, 0x67, 0xce, 0x7c, + 0xcb, 0x0f, 0x22, 0x32, 0xeb, 0xae, 0xaf, 0x93, 0x88, 0xf8, 0x0d, 0x12, 0x2b, 0x2f, 0x86, 0xd5, + 0xcb, 0x8b, 0x81, 0x9e, 0x87, 0x91, 0xdb, 0x71, 0xe0, 0x2f, 0x07, 0xae, 0x2f, 0x44, 0x10, 0xdd, + 0x08, 0x9f, 0xbc, 0xbb, 0x3b, 0x31, 0x42, 0x47, 0x54, 0xb6, 0xe3, 0x14, 0x16, 0x9a, 0x81, 0x53, + 0xb7, 0x5f, 0x5f, 0x76, 0x12, 0xc3, 0x1d, 0x20, 0x37, 0xee, 0xec, 0xc0, 0xe2, 0xea, 0xcb, 0x19, + 0x20, 0xee, 0xc6, 0xb7, 0xff, 0x66, 0x09, 0xce, 0x65, 0x5e, 0x24, 0xf0, 0xbc, 0xa0, 0x93, 0xd0, + 0x4d, 0x0d, 0xfa, 0x8a, 0x05, 0x27, 0xdb, 0x69, 0x8f, 0x43, 0x2c, 0x1c, 0xbb, 0xef, 0x2f, 0x4c, + 0x47, 0x64, 0x5c, 0x1a, 0xf5, 0x71, 0x31, 0x42, 0x27, 0x33, 0x80, 0x18, 0x77, 0xf5, 0x05, 0xbd, + 0x0a, 0xb5, 0xb6, 0xb3, 0x7d, 0x23, 0x6c, 0x3a, 0x89, 0xdc, 0x4f, 0xf6, 0x76, 0x03, 0x74, 0x12, + 0xd7, 0x9b, 0xe4, 0x47, 0xfb, 0x93, 0xf3, 0x7e, 0xb2, 0x14, 0xad, 0x24, 0x91, 0xeb, 0xb7, 0xb8, + 0x3b, 0x6f, 0x51, 0x92, 0xc1, 0x9a, 0xa2, 0xfd, 0x65, 0x2b, 0xab, 0xa4, 0xd4, 0xe8, 0x44, 0x4e, + 0x42, 0x5a, 0x3b, 0xe8, 0x23, 0x50, 0xa1, 0x1b, 0x3f, 0x39, 0x2a, 0xb7, 0x8a, 0xd4, 0x9c, 0xc6, + 0x97, 0xd0, 0x4a, 0x94, 0xfe, 0x8b, 0x31, 0x67, 0x6a, 0x7f, 0xa5, 0x96, 0x35, 0x16, 0xd8, 0xe1, + 0xed, 0x45, 0x80, 0x56, 0xb0, 0x4a, 0xda, 0xa1, 0x47, 0x87, 0xc5, 0x62, 0x27, 0x00, 0xca, 0xd7, + 0x31, 0xa7, 0x20, 0xd8, 0xc0, 0x42, 0x7f, 0xd9, 0x02, 0x68, 0xc9, 0x39, 0x2f, 0x0d, 0x81, 0x1b, + 0x45, 0xbe, 0x8e, 0x5e, 0x51, 0xba, 0x2f, 0x8a, 0x21, 0x36, 0x98, 0xa3, 0x9f, 0xb6, 0xa0, 0x9a, + 0xc8, 0xee, 0x73, 0xd5, 0xb8, 0x5a, 0x64, 0x4f, 0xe4, 0x4b, 0x6b, 0x9b, 0x48, 0x0d, 0x89, 0xe2, + 0x8b, 0x7e, 0xd6, 0x02, 0x88, 0x77, 0xfc, 0xc6, 0x72, 0xe0, 0xb9, 0x8d, 0x1d, 0xa1, 0x31, 0x6f, + 0x16, 0xea, 0x8f, 0x51, 0xd4, 0xeb, 0x63, 0x74, 0x34, 0xf4, 0x7f, 0x6c, 0x70, 0x46, 0x1f, 0x83, + 0x6a, 0x2c, 0xa6, 0x9b, 0xd0, 0x91, 0xab, 0xc5, 0x7a, 0x85, 0x38, 0x6d, 0x21, 0x5e, 0xc5, 0x3f, + 0xac, 0x78, 0xa2, 0x9f, 0xb7, 0xe0, 0x44, 0x98, 0xf6, 0xf3, 0x09, 0x75, 0x58, 0x9c, 0x0c, 0xc8, + 0xf8, 0x11, 0xeb, 0xa7, 0xef, 0xee, 0x4e, 0x9c, 0xc8, 0x34, 0xe2, 0x6c, 0x2f, 0xa8, 0x04, 0xd4, + 0x33, 0x78, 0x29, 0xe4, 0x3e, 0xc7, 0x21, 0x2d, 0x01, 0xe7, 0xb2, 0x40, 0xdc, 0x8d, 0x8f, 0x96, + 0xe1, 0x0c, 0xed, 0xdd, 0x0e, 0x37, 0x3f, 0xa5, 0x7a, 0x89, 0x99, 0x32, 0xac, 0xd6, 0x1f, 0x13, + 0x33, 0x84, 0x79, 0xf5, 0xb3, 0x38, 0x38, 0xf7, 0x49, 0xf4, 0xbb, 0x16, 0x3c, 0xe6, 0x32, 0x35, + 0x60, 0x3a, 0xcc, 0xb5, 0x46, 0x10, 0x27, 0xb1, 0xa4, 0x50, 0x59, 0xd1, 0x4b, 0xfd, 0xd4, 0xff, + 0x82, 0x78, 0x83, 0xc7, 0xe6, 0xf7, 0xe8, 0x12, 0xde, 0xb3, 0xc3, 0xe8, 0x87, 0x61, 0x54, 0xae, + 0x8b, 0x65, 0x2a, 0x82, 0x99, 0xa2, 0xad, 0xd5, 0x4f, 0xdd, 0xdd, 0x9d, 0x18, 0x5d, 0x35, 0x01, + 0x38, 0x8d, 0x67, 0x7f, 0xb3, 0x94, 0x3a, 0x0f, 0x51, 0x4e, 0x48, 0x26, 0x6e, 0x1a, 0xd2, 0xff, + 0x23, 0xa5, 0x67, 0xa1, 0xe2, 0x46, 0x79, 0x97, 0xb4, 0xb8, 0x51, 0x4d, 0x31, 0x36, 0x98, 0x53, + 0xa3, 0xf4, 0x94, 0x93, 0x75, 0x75, 0x0a, 0x09, 0xf8, 0x6a, 0x91, 0x5d, 0xea, 0x3e, 0xbd, 0x3a, + 0x27, 0xba, 0x76, 0xaa, 0x0b, 0x84, 0xbb, 0xbb, 0x64, 0x7f, 0x33, 0x7d, 0x06, 0x63, 0x2c, 0xde, + 0x3e, 0xce, 0x97, 0x3e, 0x6f, 0xc1, 0x70, 0x14, 0x78, 0x9e, 0xeb, 0xb7, 0xa8, 0xa0, 0x11, 0xda, + 0xf2, 0x83, 0xc7, 0xa2, 0xb0, 0x84, 0x44, 0x61, 0xa6, 0x2d, 0xd6, 0x3c, 0xb1, 0xd9, 0x01, 0xfb, + 0x4f, 0x2c, 0x18, 0xef, 0x25, 0x10, 0x11, 0x81, 0x77, 0xca, 0xd5, 0xae, 0xa2, 0x2b, 0x96, 0xfc, + 0x59, 0xe2, 0x11, 0xe5, 0x78, 0xae, 0xd6, 0x9f, 0x14, 0xaf, 0xf9, 0xce, 0xe5, 0xde, 0xa8, 0x78, + 0x2f, 0x3a, 0xe8, 0x15, 0x38, 0x69, 0xbc, 0x57, 0xac, 0x06, 0xa6, 0x56, 0x9f, 0xa4, 0x16, 0xc8, + 0x74, 0x06, 0x76, 0x6f, 0x77, 0xe2, 0x91, 0x6c, 0x9b, 0x90, 0xd8, 0x5d, 0x74, 0xec, 0x5f, 0x29, + 0x65, 0xbf, 0x96, 0x52, 0xb6, 0x6f, 0x59, 0x5d, 0xdb, 0xf9, 0xf7, 0x1f, 0x87, 0x82, 0x63, 0x1b, + 0x7f, 0x15, 0xc0, 0xd1, 0x1b, 0xe7, 0x01, 0x9e, 0x10, 0xdb, 0xff, 0x66, 0x00, 0xf6, 0xe8, 0x59, + 0x1f, 0xd6, 0xf3, 0x81, 0x8f, 0x15, 0x3f, 0x6b, 0xa9, 0x23, 0xa7, 0x32, 0x5b, 0xe4, 0xcd, 0xe3, + 0x1a, 0x7b, 0xbe, 0x81, 0x89, 0x79, 0x94, 0x82, 0x72, 0x63, 0xa7, 0x0f, 0xb7, 0xd0, 0x57, 0xad, + 0xf4, 0xa1, 0x19, 0x0f, 0x3b, 0x73, 0x8f, 0xad, 0x4f, 0xc6, 0x49, 0x1c, 0xef, 0x98, 0x3e, 0xbf, + 0xe9, 0x75, 0x46, 0x37, 0x09, 0xb0, 0xee, 0xfa, 0x8e, 0xe7, 0xbe, 0x41, 0xb7, 0x27, 0x15, 0xa6, + 0x61, 0x99, 0xc9, 0x72, 0x59, 0xb5, 0x62, 0x03, 0xe3, 0xfc, 0x5f, 0x82, 0x61, 0xe3, 0xcd, 0x73, + 0x82, 0x2b, 0xce, 0x98, 0xc1, 0x15, 0x35, 0x23, 0x26, 0xe2, 0xfc, 0x7b, 0xe1, 0x64, 0xb6, 0x83, + 0x07, 0x79, 0xde, 0xfe, 0x5f, 0x43, 0xd9, 0x53, 0xac, 0x55, 0x12, 0xb5, 0x69, 0xd7, 0xde, 0xf6, + 0x2c, 0xbd, 0xed, 0x59, 0x7a, 0xdb, 0xb3, 0x64, 0x1e, 0x0e, 0x08, 0xaf, 0xc9, 0xd0, 0x7d, 0xf2, + 0x9a, 0xa4, 0xfc, 0x40, 0xd5, 0xc2, 0xfd, 0x40, 0xf6, 0xdd, 0x0a, 0xa4, 0xec, 0x28, 0x3e, 0xde, + 0x3f, 0x00, 0x43, 0x11, 0x09, 0x83, 0x1b, 0x78, 0x41, 0xe8, 0x10, 0x1d, 0x6b, 0xcf, 0x9b, 0xb1, + 0x84, 0x53, 0x5d, 0x13, 0x3a, 0xc9, 0x86, 0x50, 0x22, 0x4a, 0xd7, 0x2c, 0x3b, 0xc9, 0x06, 0x66, + 0x10, 0xf4, 0x5e, 0x18, 0x4b, 0x9c, 0xa8, 0x45, 0xed, 0xed, 0x2d, 0xf6, 0x59, 0xc5, 0x59, 0xe7, + 0x23, 0x02, 0x77, 0x6c, 0x35, 0x05, 0xc5, 0x19, 0x6c, 0xf4, 0x3a, 0x0c, 0x6c, 0x10, 0xaf, 0x2d, + 0x86, 0x7c, 0xa5, 0x38, 0x19, 0xcf, 0xde, 0xf5, 0x0a, 0xf1, 0xda, 0x5c, 0x02, 0xd1, 0x5f, 0x98, + 0xb1, 0xa2, 0xf3, 0xad, 0xb6, 0xd9, 0x89, 0x93, 0xa0, 0xed, 0xbe, 0x21, 0x5d, 0x7c, 0xef, 0x2f, + 0x98, 0xf1, 0x35, 0x49, 0x9f, 0xfb, 0x52, 0xd4, 0x5f, 0xac, 0x39, 0xb3, 0x7e, 0x34, 0xdd, 0x88, + 0x7d, 0xaa, 0x1d, 0xe1, 0xa9, 0x2b, 0xba, 0x1f, 0xb3, 0x92, 0x3e, 0xef, 0x87, 0xfa, 0x8b, 0x35, + 0x67, 0xb4, 0xa3, 0xe6, 0xfd, 0x30, 0xeb, 0xc3, 0x8d, 0x82, 0xfb, 0xc0, 0xe7, 0x7c, 0xee, 0xfc, + 0x7f, 0x12, 0x2a, 0x8d, 0x0d, 0x27, 0x4a, 0xc6, 0x47, 0xd8, 0xa4, 0x51, 0x3e, 0x9d, 0x19, 0xda, + 0x88, 0x39, 0x0c, 0x3d, 0x0e, 0xe5, 0x88, 0xac, 0xb3, 0xb8, 0x4d, 0x23, 0xa2, 0x07, 0x93, 0x75, + 0x4c, 0xdb, 0xed, 0x5f, 0x2a, 0xa5, 0xcd, 0xa5, 0xf4, 0x7b, 0xf3, 0xd9, 0xde, 0xe8, 0x44, 0xb1, + 0xf4, 0xfb, 0x18, 0xb3, 0x9d, 0x35, 0x63, 0x09, 0x47, 0x9f, 0xb0, 0x60, 0xe8, 0x76, 0x1c, 0xf8, + 0x3e, 0x49, 0x84, 0x6a, 0xba, 0x59, 0xf0, 0x50, 0x5c, 0xe5, 0xd4, 0x75, 0x1f, 0x44, 0x03, 0x96, + 0x7c, 0x69, 0x77, 0xc9, 0x76, 0xc3, 0xeb, 0x34, 0xbb, 0x82, 0x34, 0x2e, 0xf1, 0x66, 0x2c, 0xe1, + 0x14, 0xd5, 0xf5, 0x39, 0xea, 0x40, 0x1a, 0x75, 0xde, 0x17, 0xa8, 0x02, 0x6e, 0xff, 0xf5, 0x41, + 0x38, 0x9b, 0xbb, 0x38, 0xa8, 0x21, 0xc3, 0x4c, 0x85, 0xcb, 0xae, 0x47, 0x64, 0x78, 0x12, 0x33, + 0x64, 0x6e, 0xaa, 0x56, 0x6c, 0x60, 0xa0, 0x9f, 0x02, 0x08, 0x9d, 0xc8, 0x69, 0x13, 0xe5, 0x97, + 0x3d, 0xb2, 0xbd, 0x40, 0xfb, 0xb1, 0x2c, 0x69, 0xea, 0xbd, 0xa9, 0x6a, 0x8a, 0xb1, 0xc1, 0x12, + 0xbd, 0x00, 0xc3, 0x11, 0xf1, 0x88, 0x13, 0xb3, 0xb0, 0xdf, 0x6c, 0x0e, 0x03, 0xd6, 0x20, 0x6c, + 0xe2, 0xa1, 0xa7, 0x54, 0x24, 0x57, 0x26, 0xa2, 0x25, 0x1d, 0xcd, 0x85, 0xde, 0xb4, 0x60, 0x6c, + 0xdd, 0xf5, 0x88, 0xe6, 0x2e, 0x32, 0x0e, 0x96, 0x8e, 0xfe, 0x92, 0x97, 0x4d, 0xba, 0x5a, 0x42, + 0xa6, 0x9a, 0x63, 0x9c, 0x61, 0x4f, 0x3f, 0xf3, 0x16, 0x89, 0x98, 0x68, 0x1d, 0x4c, 0x7f, 0xe6, + 0x9b, 0xbc, 0x19, 0x4b, 0x38, 0x9a, 0x86, 0x13, 0xa1, 0x13, 0xc7, 0x33, 0x11, 0x69, 0x12, 0x3f, + 0x71, 0x1d, 0x8f, 0xe7, 0x03, 0x54, 0x75, 0x3c, 0xf0, 0x72, 0x1a, 0x8c, 0xb3, 0xf8, 0xe8, 0x03, + 0xf0, 0x28, 0x77, 0x7c, 0x2c, 0xba, 0x71, 0xec, 0xfa, 0x2d, 0x3d, 0x0d, 0x84, 0xff, 0x67, 0x42, + 0x90, 0x7a, 0x74, 0x3e, 0x1f, 0x0d, 0xf7, 0x7a, 0x1e, 0x3d, 0x03, 0xd5, 0x78, 0xd3, 0x0d, 0x67, + 0xa2, 0x66, 0xcc, 0x0e, 0x3d, 0xaa, 0xda, 0xdb, 0xb8, 0x22, 0xda, 0xb1, 0xc2, 0x40, 0x0d, 0x18, + 0xe1, 0x9f, 0x84, 0x87, 0xa2, 0x09, 0xf9, 0xf8, 0x6c, 0x4f, 0xf5, 0x28, 0xd2, 0xdb, 0x26, 0xb1, + 0x73, 0xe7, 0x92, 0x3c, 0x82, 0xe1, 0x27, 0x06, 0x37, 0x0d, 0x32, 0x38, 0x45, 0xd4, 0xfe, 0x85, + 0x52, 0x7a, 0xc7, 0x6d, 0x2e, 0x52, 0x14, 0xd3, 0xa5, 0x98, 0xdc, 0x74, 0x22, 0xe9, 0x8d, 0x39, + 0x62, 0xda, 0x82, 0xa0, 0x7b, 0xd3, 0x89, 0xcc, 0x45, 0xcd, 0x18, 0x60, 0xc9, 0x09, 0xdd, 0x86, + 0x81, 0xc4, 0x73, 0x0a, 0xca, 0x73, 0x32, 0x38, 0x6a, 0x07, 0xc8, 0xc2, 0x74, 0x8c, 0x19, 0x0f, + 0xf4, 0x18, 0xb5, 0xfa, 0xd7, 0xe4, 0x11, 0x89, 0x30, 0xd4, 0xd7, 0x62, 0xcc, 0x5a, 0xed, 0x7b, + 0x90, 0x23, 0x57, 0x95, 0x22, 0x43, 0x17, 0x01, 0xe8, 0x06, 0x72, 0x39, 0x22, 0xeb, 0xee, 0xb6, + 0x30, 0x24, 0xd4, 0xda, 0xbd, 0xae, 0x20, 0xd8, 0xc0, 0x92, 0xcf, 0xac, 0x74, 0xd6, 0xe9, 0x33, + 0xa5, 0xee, 0x67, 0x38, 0x04, 0x1b, 0x58, 0xe8, 0x79, 0x18, 0x74, 0xdb, 0x4e, 0x4b, 0x85, 0x60, + 0x3e, 0x46, 0x17, 0xed, 0x3c, 0x6b, 0xb9, 0xb7, 0x3b, 0x31, 0xa6, 0x3a, 0xc4, 0x9a, 0xb0, 0xc0, + 0x45, 0xbf, 0x62, 0xc1, 0x48, 0x23, 0x68, 0xb7, 0x03, 0x9f, 0x6f, 0xbb, 0xc4, 0x1e, 0xf2, 0xf6, + 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, 0xb3, 0x08, + 0xb8, 0xfb, 0x19, 0x74, 0x13, 0x1e, 0x31, 0x1a, 0xcd, 0x71, 0xe0, 0xb2, 0xe9, 0x09, 0x41, 0xed, + 0x91, 0xcb, 0xb9, 0x58, 0xb8, 0xc7, 0xd3, 0x69, 0x87, 0x49, 0xad, 0x0f, 0x87, 0xc9, 0x6b, 0x70, + 0xae, 0xd1, 0x3d, 0x32, 0x5b, 0x71, 0x67, 0x2d, 0xe6, 0x92, 0xaa, 0x5a, 0xff, 0x3e, 0x41, 0xe0, + 0xdc, 0x4c, 0x2f, 0x44, 0xdc, 0x9b, 0x06, 0xfa, 0x08, 0x54, 0x23, 0xc2, 0xbe, 0x4a, 0x2c, 0x12, + 0x71, 0x8e, 0xb8, 0x4b, 0xd6, 0x16, 0x28, 0x27, 0xab, 0x65, 0xaf, 0x68, 0x88, 0xb1, 0xe2, 0x88, + 0xee, 0xc0, 0x50, 0xe8, 0x24, 0x8d, 0x0d, 0x91, 0x7e, 0x73, 0xe4, 0xf8, 0x17, 0xc5, 0x9c, 0xf9, + 0xc0, 0x8d, 0x84, 0x5d, 0xce, 0x04, 0x4b, 0x6e, 0xd4, 0x1a, 0x69, 0x04, 0xed, 0x30, 0xf0, 0x89, + 0x9f, 0xc4, 0xe3, 0xa3, 0xda, 0x1a, 0x99, 0x51, 0xad, 0xd8, 0xc0, 0x40, 0xcb, 0x70, 0x86, 0xf9, + 0x8c, 0x6e, 0xb9, 0xc9, 0x46, 0xd0, 0x49, 0xe4, 0x16, 0x68, 0x7c, 0x2c, 0x7d, 0x54, 0xb1, 0x90, + 0x83, 0x83, 0x73, 0x9f, 0x3c, 0xff, 0x3e, 0x38, 0xd5, 0xb5, 0x94, 0x0f, 0xe4, 0xae, 0x99, 0x85, + 0x47, 0xf2, 0x17, 0xcd, 0x81, 0x9c, 0x36, 0xff, 0x38, 0x13, 0x36, 0x6b, 0x18, 0xd2, 0x7d, 0x38, + 0x00, 0x1d, 0x28, 0x13, 0x7f, 0x4b, 0xe8, 0x90, 0xcb, 0x47, 0xfb, 0x76, 0x97, 0xfc, 0x2d, 0xbe, + 0xe6, 0x99, 0x97, 0xe3, 0x92, 0xbf, 0x85, 0x29, 0x6d, 0xf4, 0x45, 0x2b, 0x65, 0x08, 0x72, 0xb7, + 0xe1, 0x87, 0x8e, 0x65, 0xe7, 0xd0, 0xb7, 0x6d, 0x68, 0xff, 0xdb, 0x12, 0x5c, 0xd8, 0x8f, 0x48, + 0x1f, 0xc3, 0xf7, 0x24, 0x0c, 0xc6, 0xec, 0x20, 0x5c, 0x08, 0xe5, 0x61, 0x3a, 0x57, 0xf9, 0xd1, + 0xf8, 0x6b, 0x58, 0x80, 0x90, 0x07, 0xe5, 0xb6, 0x13, 0x0a, 0x6f, 0xd2, 0xfc, 0x51, 0x13, 0x69, + 0xe8, 0x7f, 0xc7, 0x5b, 0x74, 0x42, 0xee, 0xa3, 0x30, 0x1a, 0x30, 0x65, 0x83, 0x12, 0xa8, 0x38, + 0x51, 0xe4, 0xc8, 0x53, 0xd7, 0x6b, 0xc5, 0xf0, 0x9b, 0xa6, 0x24, 0xf9, 0xa1, 0x55, 0xaa, 0x09, + 0x73, 0x66, 0xf6, 0x67, 0x87, 0x52, 0xc9, 0x24, 0xec, 0x28, 0x3d, 0x86, 0x41, 0xe1, 0x44, 0xb2, + 0x8a, 0xce, 0x5f, 0xe2, 0xd9, 0x80, 0x6c, 0x9f, 0x28, 0x72, 0xaa, 0x05, 0x2b, 0xf4, 0x19, 0x8b, + 0x65, 0x2e, 0xcb, 0x04, 0x1b, 0xb1, 0x3b, 0x3b, 0x9e, 0x44, 0x6a, 0x33, 0x1f, 0x5a, 0x36, 0x62, + 0x93, 0xbb, 0xa8, 0x40, 0xc0, 0xac, 0xd2, 0xee, 0x0a, 0x04, 0xcc, 0xca, 0x94, 0x70, 0xb4, 0x9d, + 0x73, 0x64, 0x5e, 0x40, 0xf6, 0x6b, 0x1f, 0x87, 0xe4, 0x5f, 0xb5, 0xe0, 0x94, 0x9b, 0x3d, 0xfb, + 0x14, 0x7b, 0x99, 0x23, 0x06, 0x65, 0xf4, 0x3e, 0x5a, 0x55, 0xea, 0xbc, 0x0b, 0x84, 0xbb, 0x3b, + 0x83, 0x9a, 0x30, 0xe0, 0xfa, 0xeb, 0x81, 0x30, 0x62, 0xea, 0x47, 0xeb, 0xd4, 0xbc, 0xbf, 0x1e, + 0xe8, 0xd5, 0x4c, 0xff, 0x61, 0x46, 0x1d, 0x2d, 0xc0, 0x99, 0x48, 0x78, 0x9b, 0xae, 0xb8, 0x71, + 0x12, 0x44, 0x3b, 0x0b, 0x6e, 0xdb, 0x4d, 0x98, 0x01, 0x52, 0xae, 0x8f, 0x53, 0xfd, 0x80, 0x73, + 0xe0, 0x38, 0xf7, 0x29, 0xf4, 0x06, 0x0c, 0xc9, 0x54, 0xeb, 0x6a, 0x11, 0xfb, 0xc2, 0xee, 0xf9, + 0xaf, 0x26, 0xd3, 0x8a, 0xc8, 0xaa, 0x96, 0x0c, 0xed, 0x37, 0x87, 0xa1, 0xfb, 0x58, 0x14, 0x7d, + 0x14, 0x6a, 0x91, 0x4a, 0xff, 0xb6, 0x8a, 0x50, 0xd7, 0xf2, 0xfb, 0x8a, 0x23, 0x59, 0x65, 0x0a, + 0xe9, 0x44, 0x6f, 0xcd, 0x91, 0x6e, 0x58, 0x62, 0x7d, 0x7a, 0x5a, 0xc0, 0xdc, 0x16, 0x5c, 0xf5, + 0xc9, 0xd8, 0x8e, 0xdf, 0xc0, 0x8c, 0x07, 0x8a, 0x60, 0x70, 0x83, 0x38, 0x5e, 0xb2, 0x51, 0x8c, + 0x13, 0xff, 0x0a, 0xa3, 0x95, 0x4d, 0x02, 0xe2, 0xad, 0x58, 0x70, 0x42, 0xdb, 0x30, 0xb4, 0xc1, + 0x27, 0x80, 0xd8, 0x43, 0x2c, 0x1e, 0x75, 0x70, 0x53, 0xb3, 0x4a, 0x7f, 0x6e, 0xd1, 0x80, 0x25, + 0x3b, 0x16, 0x6f, 0x63, 0x44, 0x04, 0xf0, 0xa5, 0x5b, 0x5c, 0xfe, 0x53, 0xff, 0xe1, 0x00, 0x1f, + 0x86, 0x91, 0x88, 0x34, 0x02, 0xbf, 0xe1, 0x7a, 0xa4, 0x39, 0x2d, 0x1d, 0xf4, 0x07, 0xc9, 0x9a, + 0x61, 0xfb, 0x70, 0x6c, 0xd0, 0xc0, 0x29, 0x8a, 0xe8, 0xd3, 0x16, 0x8c, 0xa9, 0x9c, 0x51, 0xfa, + 0x41, 0x88, 0x70, 0x08, 0x2f, 0x14, 0x94, 0xa1, 0xca, 0x68, 0xd6, 0xd1, 0xdd, 0xdd, 0x89, 0xb1, + 0x74, 0x1b, 0xce, 0xf0, 0x45, 0xaf, 0x00, 0x04, 0x6b, 0x3c, 0xa8, 0x66, 0x3a, 0x11, 0xde, 0xe1, + 0x83, 0xbc, 0xea, 0x18, 0x4f, 0x9f, 0x93, 0x14, 0xb0, 0x41, 0x0d, 0x5d, 0x03, 0xe0, 0xcb, 0x66, + 0x75, 0x27, 0x94, 0x1b, 0x0d, 0x99, 0xf6, 0x04, 0x2b, 0x0a, 0x72, 0x6f, 0x77, 0xa2, 0xdb, 0x5b, + 0xc7, 0x02, 0x17, 0x8c, 0xc7, 0xd1, 0x4f, 0xc2, 0x50, 0xdc, 0x69, 0xb7, 0x1d, 0xe5, 0x3b, 0x2e, + 0x30, 0x21, 0x8f, 0xd3, 0x35, 0x44, 0x11, 0x6f, 0xc0, 0x92, 0x23, 0xba, 0x4d, 0x85, 0x6a, 0x2c, + 0xdc, 0x88, 0x6c, 0x15, 0x71, 0x9b, 0x60, 0x98, 0xbd, 0xd3, 0x7b, 0xa4, 0xe1, 0x8d, 0x73, 0x70, + 0xee, 0xed, 0x4e, 0x3c, 0x92, 0x6e, 0x5f, 0x08, 0x44, 0x8a, 0x5c, 0x2e, 0x4d, 0x74, 0x55, 0x56, + 0x5e, 0xa1, 0xaf, 0x2d, 0x0b, 0x02, 0x3c, 0xad, 0x2b, 0xaf, 0xb0, 0xe6, 0xde, 0x63, 0x66, 0x3e, + 0x8c, 0x16, 0xe1, 0x74, 0x23, 0xf0, 0x93, 0x28, 0xf0, 0x3c, 0x5e, 0x79, 0x88, 0xef, 0xf9, 0xb8, + 0x6f, 0xf9, 0x9d, 0xa2, 0xdb, 0xa7, 0x67, 0xba, 0x51, 0x70, 0xde, 0x73, 0xb6, 0x9f, 0x8e, 0x36, + 0x14, 0x83, 0xf3, 0x3c, 0x8c, 0x90, 0xed, 0x84, 0x44, 0xbe, 0xe3, 0xdd, 0xc0, 0x0b, 0xd2, 0xab, + 0xca, 0xd6, 0xc0, 0x25, 0xa3, 0x1d, 0xa7, 0xb0, 0x90, 0xad, 0x1c, 0x1d, 0x46, 0xda, 0x27, 0x77, + 0x74, 0x48, 0xb7, 0x86, 0xfd, 0xbf, 0x4b, 0x29, 0x83, 0x6c, 0x35, 0x22, 0x04, 0x05, 0x50, 0xf1, + 0x83, 0xa6, 0x92, 0xfd, 0x57, 0x8b, 0x91, 0xfd, 0xd7, 0x83, 0xa6, 0x51, 0x9e, 0x85, 0xfe, 0x8b, + 0x31, 0xe7, 0xc3, 0xea, 0x57, 0xc8, 0x42, 0x1f, 0x0c, 0x20, 0x36, 0x1a, 0x45, 0x72, 0x56, 0xf5, + 0x2b, 0x96, 0x4c, 0x46, 0x38, 0xcd, 0x17, 0x6d, 0x42, 0x65, 0x23, 0x88, 0x13, 0xb9, 0xfd, 0x38, + 0xe2, 0x4e, 0xe7, 0x4a, 0x10, 0x27, 0xcc, 0x8a, 0x50, 0xaf, 0x4d, 0x5b, 0x62, 0xcc, 0x79, 0xd8, + 0xff, 0xc5, 0x4a, 0xf9, 0xd0, 0x6f, 0xb1, 0xc8, 0xdb, 0x2d, 0xe2, 0xd3, 0x65, 0x6d, 0x86, 0x1a, + 0xfd, 0x70, 0x26, 0x8f, 0xf1, 0x5d, 0xbd, 0x0a, 0x6b, 0xdd, 0xa1, 0x14, 0x26, 0x19, 0x09, 0x23, + 0x2a, 0xe9, 0xe3, 0x56, 0x3a, 0xa3, 0xb4, 0x54, 0xc4, 0x06, 0xc3, 0xcc, 0xaa, 0xde, 0x37, 0x39, + 0xd5, 0xfe, 0xa2, 0x05, 0x43, 0x75, 0xa7, 0xb1, 0x19, 0xac, 0xaf, 0xa3, 0x67, 0xa0, 0xda, 0xec, + 0x44, 0x66, 0x72, 0xab, 0x72, 0x1c, 0xcc, 0x8a, 0x76, 0xac, 0x30, 0xe8, 0x1c, 0x5e, 0x77, 0x1a, + 0x32, 0xb7, 0xba, 0xcc, 0xe7, 0xf0, 0x65, 0xd6, 0x82, 0x05, 0x04, 0xbd, 0x00, 0xc3, 0x6d, 0x67, + 0x5b, 0x3e, 0x9c, 0x75, 0xe0, 0x2f, 0x6a, 0x10, 0x36, 0xf1, 0xec, 0x7f, 0x69, 0xc1, 0x78, 0xdd, + 0x89, 0xdd, 0xc6, 0x74, 0x27, 0xd9, 0xa8, 0xbb, 0xc9, 0x5a, 0xa7, 0xb1, 0x49, 0x12, 0x9e, 0x50, + 0x4f, 0x7b, 0xd9, 0x89, 0xe9, 0x52, 0x52, 0xfb, 0x3a, 0xd5, 0xcb, 0x1b, 0xa2, 0x1d, 0x2b, 0x0c, + 0xf4, 0x06, 0x0c, 0x87, 0x4e, 0x1c, 0xdf, 0x09, 0xa2, 0x26, 0x26, 0xeb, 0xc5, 0x94, 0xb3, 0x58, + 0x21, 0x8d, 0x88, 0x24, 0x98, 0xac, 0x8b, 0x43, 0x66, 0x4d, 0x1f, 0x9b, 0xcc, 0xec, 0xcf, 0x5b, + 0x70, 0xae, 0x4e, 0x9c, 0x88, 0x44, 0xac, 0xfa, 0x85, 0x7a, 0x91, 0x19, 0x2f, 0xe8, 0x34, 0xd1, + 0xeb, 0x50, 0x4d, 0x68, 0x33, 0xed, 0x96, 0x55, 0x6c, 0xb7, 0xd8, 0x19, 0xf1, 0xaa, 0x20, 0x8e, + 0x15, 0x1b, 0xfb, 0x6f, 0x58, 0x30, 0xc2, 0x8e, 0xdb, 0x66, 0x49, 0xe2, 0xb8, 0x5e, 0x57, 0x91, + 0x28, 0xab, 0xcf, 0x22, 0x51, 0x17, 0x60, 0x60, 0x23, 0x68, 0x93, 0xec, 0x51, 0xf1, 0x95, 0x80, + 0x6e, 0xab, 0x29, 0x04, 0x3d, 0x47, 0x3f, 0xbc, 0xeb, 0x27, 0x0e, 0x5d, 0x02, 0xd2, 0x9d, 0x7b, + 0x82, 0x7f, 0x74, 0xd5, 0x8c, 0x4d, 0x1c, 0xfb, 0xb7, 0x6a, 0x30, 0x24, 0xe2, 0x09, 0xfa, 0x2e, + 0xaa, 0x20, 0xf7, 0xf7, 0xa5, 0x9e, 0xfb, 0xfb, 0x18, 0x06, 0x1b, 0xac, 0x5a, 0x9d, 0x30, 0x23, + 0xaf, 0x15, 0x12, 0x80, 0xc2, 0x0b, 0xe0, 0xe9, 0x6e, 0xf1, 0xff, 0x58, 0xb0, 0x42, 0x5f, 0xb0, + 0xe0, 0x44, 0x23, 0xf0, 0x7d, 0xd2, 0xd0, 0x36, 0xce, 0x40, 0x11, 0x71, 0x06, 0x33, 0x69, 0xa2, + 0xfa, 0xac, 0x27, 0x03, 0xc0, 0x59, 0xf6, 0xe8, 0x25, 0x18, 0xe5, 0x63, 0x76, 0x33, 0xe5, 0x83, + 0xd6, 0xb5, 0x83, 0x4c, 0x20, 0x4e, 0xe3, 0xa2, 0x49, 0xee, 0xcb, 0x17, 0x55, 0x7a, 0x06, 0xb5, + 0xab, 0xce, 0xa8, 0xcf, 0x63, 0x60, 0xa0, 0x08, 0x50, 0x44, 0xd6, 0x23, 0x12, 0x6f, 0x88, 0x78, + 0x0b, 0x66, 0x5f, 0x0d, 0x1d, 0x2e, 0x01, 0x1b, 0x77, 0x51, 0xc2, 0x39, 0xd4, 0xd1, 0xa6, 0xd8, + 0x60, 0x56, 0x8b, 0x90, 0xa1, 0xe2, 0x33, 0xf7, 0xdc, 0x67, 0x4e, 0x40, 0x25, 0xde, 0x70, 0xa2, + 0x26, 0xb3, 0xeb, 0xca, 0x3c, 0xe9, 0x67, 0x85, 0x36, 0x60, 0xde, 0x8e, 0x66, 0xe1, 0x64, 0xa6, + 0xf2, 0x51, 0x2c, 0x7c, 0xc5, 0x2a, 0xc1, 0x23, 0x53, 0x33, 0x29, 0xc6, 0x5d, 0x4f, 0x98, 0xce, + 0x87, 0xe1, 0x7d, 0x9c, 0x0f, 0x3b, 0x2a, 0xaa, 0x8f, 0x7b, 0x71, 0x5f, 0x2e, 0x64, 0x00, 0xfa, + 0x0a, 0xe1, 0xfb, 0x5c, 0x26, 0x84, 0x6f, 0x94, 0x75, 0xe0, 0x66, 0x31, 0x1d, 0x38, 0x78, 0xbc, + 0xde, 0x83, 0x8c, 0xbf, 0xfb, 0x73, 0x0b, 0xe4, 0x77, 0x9d, 0x71, 0x1a, 0x1b, 0x84, 0x4e, 0x19, + 0xf4, 0x5e, 0x18, 0x53, 0x5b, 0xe8, 0x99, 0xa0, 0xe3, 0xf3, 0xd0, 0xbb, 0xb2, 0x3e, 0x14, 0xc6, + 0x29, 0x28, 0xce, 0x60, 0xa3, 0x29, 0xa8, 0xd1, 0x71, 0xe2, 0x8f, 0x72, 0x5d, 0xab, 0xb6, 0xe9, + 0xd3, 0xcb, 0xf3, 0xe2, 0x29, 0x8d, 0x83, 0x02, 0x38, 0xe5, 0x39, 0x71, 0xc2, 0x7a, 0x40, 0x77, + 0xd4, 0x87, 0x2c, 0x7f, 0xc0, 0xb2, 0x08, 0x16, 0xb2, 0x84, 0x70, 0x37, 0x6d, 0xfb, 0x5b, 0x03, + 0x30, 0x9a, 0x92, 0x8c, 0x07, 0x54, 0xd2, 0xcf, 0x40, 0x55, 0xea, 0xcd, 0x6c, 0xa1, 0x16, 0xa5, + 0x5c, 0x15, 0x06, 0x55, 0x5a, 0x6b, 0x5a, 0xab, 0x66, 0x8d, 0x0a, 0x43, 0xe1, 0x62, 0x13, 0x8f, + 0x09, 0xe5, 0xc4, 0x8b, 0x67, 0x3c, 0x97, 0xf8, 0x09, 0xef, 0x66, 0x31, 0x42, 0x79, 0x75, 0x61, + 0xc5, 0x24, 0xaa, 0x85, 0x72, 0x06, 0x80, 0xb3, 0xec, 0xd1, 0xa7, 0x2c, 0x18, 0x75, 0xee, 0xc4, + 0xba, 0xa4, 0xaa, 0x08, 0xd6, 0x3b, 0xa2, 0x92, 0x4a, 0x55, 0x69, 0xe5, 0x2e, 0xdf, 0x54, 0x13, + 0x4e, 0x33, 0x45, 0x6f, 0x59, 0x80, 0xc8, 0x36, 0x69, 0xc8, 0x70, 0x42, 0xd1, 0x97, 0xc1, 0x22, + 0x76, 0x9a, 0x97, 0xba, 0xe8, 0x72, 0xa9, 0xde, 0xdd, 0x8e, 0x73, 0xfa, 0x60, 0xff, 0xb3, 0xb2, + 0x5a, 0x50, 0x3a, 0x82, 0xd5, 0x31, 0x22, 0xe9, 0xac, 0xc3, 0x47, 0xd2, 0xe9, 0x88, 0x84, 0xee, + 0xac, 0xca, 0x54, 0x12, 0x56, 0xe9, 0x01, 0x25, 0x61, 0xfd, 0xb4, 0x95, 0x2a, 0x49, 0x34, 0x7c, + 0xf1, 0x95, 0x62, 0xa3, 0x67, 0x27, 0x79, 0xb4, 0x44, 0x46, 0xba, 0xa7, 0x83, 0x64, 0xa8, 0x34, + 0x35, 0xd0, 0x0e, 0x24, 0x0d, 0xff, 0x7d, 0x19, 0x86, 0x0d, 0x4d, 0x9a, 0x6b, 0x16, 0x59, 0x0f, + 0x99, 0x59, 0x54, 0x3a, 0x80, 0x59, 0xf4, 0x53, 0x50, 0x6b, 0x48, 0x29, 0x5f, 0x4c, 0x51, 0xde, + 0xac, 0xee, 0xd0, 0x82, 0x5e, 0x35, 0x61, 0xcd, 0x13, 0xcd, 0xa5, 0x52, 0x77, 0x84, 0x86, 0x18, + 0x60, 0x1a, 0x22, 0x2f, 0xb7, 0x46, 0x68, 0x8a, 0xee, 0x67, 0x58, 0xe5, 0xaa, 0xd0, 0x15, 0xef, + 0x25, 0x63, 0xdc, 0x79, 0xe5, 0xaa, 0xe5, 0x79, 0xd9, 0x8c, 0x4d, 0x1c, 0xfb, 0x5b, 0x96, 0xfa, + 0xb8, 0xf7, 0xa1, 0x46, 0xc3, 0xed, 0x74, 0x8d, 0x86, 0x4b, 0x85, 0x0c, 0x73, 0x8f, 0xe2, 0x0c, + 0xd7, 0x61, 0x68, 0x26, 0x68, 0xb7, 0x1d, 0xbf, 0x89, 0xbe, 0x1f, 0x86, 0x1a, 0xfc, 0xa7, 0x70, + 0xec, 0xb0, 0xe3, 0x41, 0x01, 0xc5, 0x12, 0x86, 0x1e, 0x83, 0x01, 0x27, 0x6a, 0x49, 0x67, 0x0e, + 0x0b, 0xae, 0x99, 0x8e, 0x5a, 0x31, 0x66, 0xad, 0xf6, 0x3f, 0x1a, 0x00, 0x76, 0xa6, 0xed, 0x44, + 0xa4, 0xb9, 0x1a, 0xb0, 0xa2, 0x80, 0xc7, 0x7a, 0xa8, 0xa6, 0x37, 0x4b, 0x0f, 0xf3, 0xc1, 0x9a, + 0x71, 0xb8, 0x52, 0xbe, 0xcf, 0x87, 0x2b, 0x3d, 0xce, 0xcb, 0x06, 0x1e, 0xa2, 0xf3, 0x32, 0xfb, + 0xb3, 0x16, 0x20, 0x15, 0x08, 0xa1, 0x0f, 0xb4, 0xa7, 0xa0, 0xa6, 0x42, 0x22, 0x84, 0x61, 0xa5, + 0x45, 0x84, 0x04, 0x60, 0x8d, 0xd3, 0xc7, 0x0e, 0xf9, 0x49, 0x29, 0xbf, 0xcb, 0xe9, 0xb8, 0x5c, + 0x26, 0xf5, 0x85, 0x38, 0xb7, 0x7f, 0xbb, 0x04, 0x8f, 0x70, 0x95, 0xbc, 0xe8, 0xf8, 0x4e, 0x8b, + 0xb4, 0x69, 0xaf, 0xfa, 0x0d, 0x51, 0x68, 0xd0, 0xad, 0x99, 0x2b, 0xe3, 0x6c, 0x8f, 0xba, 0x76, + 0xf9, 0x9a, 0xe3, 0xab, 0x6c, 0xde, 0x77, 0x13, 0xcc, 0x88, 0xa3, 0x18, 0xaa, 0xb2, 0x62, 0xbd, + 0x90, 0xc5, 0x05, 0x31, 0x52, 0x62, 0x49, 0xe8, 0x4d, 0x82, 0x15, 0x23, 0x6a, 0xb8, 0x7a, 0x41, + 0x63, 0x13, 0x93, 0x30, 0x60, 0x72, 0xd7, 0x08, 0x73, 0x5c, 0x10, 0xed, 0x58, 0x61, 0xd8, 0xbf, + 0x6d, 0x41, 0x56, 0x23, 0x19, 0xd5, 0xd7, 0xac, 0x3d, 0xab, 0xaf, 0x1d, 0xa0, 0xfc, 0xd9, 0x4f, + 0xc0, 0xb0, 0x93, 0x50, 0x23, 0x82, 0x6f, 0xbb, 0xcb, 0x87, 0x3b, 0xd6, 0x58, 0x0c, 0x9a, 0xee, + 0xba, 0xcb, 0xb6, 0xdb, 0x26, 0x39, 0xfb, 0x7f, 0x0c, 0xc0, 0xa9, 0xae, 0x6c, 0x10, 0xf4, 0x22, + 0x8c, 0x34, 0xc4, 0xf4, 0x08, 0xa5, 0x43, 0xab, 0x66, 0x86, 0xc5, 0x69, 0x18, 0x4e, 0x61, 0xf6, + 0x31, 0x41, 0xe7, 0xe1, 0x74, 0x44, 0x37, 0xfa, 0x1d, 0x32, 0xbd, 0x9e, 0x90, 0x68, 0x85, 0x34, + 0x02, 0xbf, 0xc9, 0x6b, 0x04, 0x96, 0xeb, 0x8f, 0xde, 0xdd, 0x9d, 0x38, 0x8d, 0xbb, 0xc1, 0x38, + 0xef, 0x19, 0x14, 0xc2, 0xa8, 0x67, 0xda, 0x80, 0x62, 0x03, 0x70, 0x28, 0xf3, 0x51, 0xd9, 0x08, + 0xa9, 0x66, 0x9c, 0x66, 0x90, 0x36, 0x24, 0x2b, 0x0f, 0xc8, 0x90, 0xfc, 0xa4, 0x36, 0x24, 0xf9, + 0xf9, 0xfb, 0x07, 0x0b, 0xce, 0x06, 0x3a, 0x6e, 0x4b, 0xf2, 0x65, 0xa8, 0xca, 0xd8, 0xa4, 0xbe, + 0x62, 0x7a, 0x4c, 0x3a, 0x3d, 0x24, 0xda, 0xbd, 0x12, 0xe4, 0x6c, 0x42, 0xe8, 0x3a, 0xd3, 0x1a, + 0x3f, 0xb5, 0xce, 0x0e, 0xa6, 0xf5, 0xd1, 0x36, 0x8f, 0xcb, 0xe2, 0xba, 0xed, 0x03, 0x45, 0x6f, + 0xa2, 0x74, 0xa8, 0x96, 0x4a, 0x92, 0x50, 0xe1, 0x5a, 0x17, 0x01, 0xb4, 0xa1, 0x26, 0x42, 0xe0, + 0xd5, 0xb1, 0xaf, 0xb6, 0xe7, 0xb0, 0x81, 0x45, 0xf7, 0xd4, 0xae, 0x1f, 0x27, 0x8e, 0xe7, 0x5d, + 0x71, 0xfd, 0x44, 0x38, 0x07, 0x95, 0x12, 0x9f, 0xd7, 0x20, 0x6c, 0xe2, 0x9d, 0x7f, 0x8f, 0xf1, + 0x5d, 0x0e, 0xf2, 0x3d, 0x37, 0xe0, 0xdc, 0x9c, 0x9b, 0xa8, 0xc4, 0x0d, 0x35, 0x8f, 0xa8, 0x1d, + 0xa6, 0x12, 0x91, 0xac, 0x9e, 0x89, 0x48, 0x46, 0xe2, 0x44, 0x29, 0x9d, 0xe7, 0x91, 0x4d, 0x9c, + 0xb0, 0x5f, 0x84, 0x33, 0x73, 0x6e, 0x72, 0xd9, 0xf5, 0xc8, 0x01, 0x99, 0xd8, 0xbf, 0x39, 0x08, + 0x23, 0x66, 0xea, 0xdf, 0x41, 0x72, 0xa9, 0x3e, 0x4f, 0x4d, 0x2d, 0xf1, 0x76, 0xae, 0x3a, 0x34, + 0xbb, 0x75, 0xe4, 0x3c, 0xc4, 0xfc, 0x11, 0x33, 0xac, 0x2d, 0xcd, 0x13, 0x9b, 0x1d, 0x40, 0x77, + 0xa0, 0xb2, 0xce, 0x02, 0xfb, 0xcb, 0x45, 0x44, 0x16, 0xe4, 0x8d, 0xa8, 0x5e, 0x66, 0x3c, 0x35, + 0x80, 0xf3, 0xa3, 0x1a, 0x32, 0x4a, 0x67, 0x8b, 0x19, 0xc1, 0xa8, 0x22, 0x4f, 0x4c, 0x61, 0xf4, + 0x12, 0xf5, 0x95, 0x43, 0x88, 0xfa, 0x94, 0xe0, 0x1d, 0x7c, 0x40, 0x82, 0x97, 0x25, 0x69, 0x24, + 0x1b, 0xcc, 0x7e, 0x13, 0xd1, 0xf3, 0x43, 0x6c, 0x10, 0x8c, 0x24, 0x8d, 0x14, 0x18, 0x67, 0xf1, + 0xd1, 0xc7, 0x94, 0xe8, 0xae, 0x16, 0xe1, 0x57, 0x35, 0x67, 0xf4, 0x71, 0x4b, 0xed, 0xcf, 0x96, + 0x60, 0x6c, 0xce, 0xef, 0x2c, 0xcf, 0x2d, 0x77, 0xd6, 0x3c, 0xb7, 0x71, 0x8d, 0xec, 0x50, 0xd1, + 0xbc, 0x49, 0x76, 0xe6, 0x67, 0xc5, 0x0a, 0x52, 0x73, 0xe6, 0x1a, 0x6d, 0xc4, 0x1c, 0x46, 0x85, + 0xd1, 0xba, 0xeb, 0xb7, 0x48, 0x14, 0x46, 0xae, 0x70, 0x79, 0x1a, 0xc2, 0xe8, 0xb2, 0x06, 0x61, + 0x13, 0x8f, 0xd2, 0x0e, 0xee, 0xf8, 0x24, 0xca, 0x1a, 0xb2, 0x4b, 0xb4, 0x11, 0x73, 0x18, 0x45, + 0x4a, 0xa2, 0x4e, 0x9c, 0x88, 0xc9, 0xa8, 0x90, 0x56, 0x69, 0x23, 0xe6, 0x30, 0xba, 0xd2, 0xe3, + 0xce, 0x1a, 0x0b, 0xdc, 0xc8, 0x84, 0xea, 0xaf, 0xf0, 0x66, 0x2c, 0xe1, 0x14, 0x75, 0x93, 0xec, + 0xcc, 0xd2, 0x5d, 0x6f, 0x26, 0x63, 0xe7, 0x1a, 0x6f, 0xc6, 0x12, 0xce, 0x8a, 0x1b, 0xa6, 0x87, + 0xe3, 0xbb, 0xae, 0xb8, 0x61, 0xba, 0xfb, 0x3d, 0xf6, 0xcf, 0xbf, 0x6c, 0xc1, 0x88, 0x19, 0x6e, + 0x85, 0x5a, 0x19, 0x1b, 0x77, 0xa9, 0xab, 0x36, 0xee, 0x8f, 0xe5, 0x5d, 0x2c, 0xd6, 0x72, 0x93, + 0x20, 0x8c, 0x9f, 0x25, 0x7e, 0xcb, 0xf5, 0x09, 0x3b, 0x45, 0xe7, 0x61, 0x5a, 0xa9, 0x58, 0xae, + 0x99, 0xa0, 0x49, 0x0e, 0x61, 0x24, 0xdb, 0xb7, 0xe0, 0x54, 0x57, 0x9a, 0x56, 0x1f, 0xa6, 0xc5, + 0xbe, 0x49, 0xb2, 0x36, 0x86, 0x61, 0x4a, 0x58, 0x16, 0xd8, 0x99, 0x81, 0x53, 0x7c, 0x21, 0x51, + 0x4e, 0x2b, 0x8d, 0x0d, 0xd2, 0x56, 0xa9, 0x77, 0xcc, 0xbf, 0x7e, 0x33, 0x0b, 0xc4, 0xdd, 0xf8, + 0xf6, 0xe7, 0x2c, 0x18, 0x4d, 0x65, 0xce, 0x15, 0x64, 0x04, 0xb1, 0x95, 0x16, 0xb0, 0xe8, 0x3f, + 0x16, 0x02, 0x5d, 0x66, 0xca, 0x54, 0xaf, 0x34, 0x0d, 0xc2, 0x26, 0x9e, 0xfd, 0xc5, 0x12, 0x54, + 0x65, 0x04, 0x45, 0x1f, 0x5d, 0xf9, 0x8c, 0x05, 0xa3, 0xea, 0x4c, 0x83, 0x39, 0xcb, 0x4a, 0x45, + 0xa4, 0x39, 0xd0, 0x1e, 0xa8, 0xed, 0xb6, 0xbf, 0x1e, 0x68, 0x8b, 0x1c, 0x9b, 0xcc, 0x70, 0x9a, + 0x37, 0xba, 0x09, 0x10, 0xef, 0xc4, 0x09, 0x69, 0x1b, 0x6e, 0x3b, 0xdb, 0x58, 0x71, 0x93, 0x8d, + 0x20, 0x22, 0x74, 0x7d, 0x5d, 0x0f, 0x9a, 0x64, 0x45, 0x61, 0x6a, 0x13, 0x4a, 0xb7, 0x61, 0x83, + 0x92, 0xfd, 0x0f, 0x4a, 0x70, 0x32, 0xdb, 0x25, 0xf4, 0x41, 0x18, 0x91, 0xdc, 0x8d, 0x3b, 0xd2, + 0x64, 0xd8, 0xc8, 0x08, 0x36, 0x60, 0xf7, 0x76, 0x27, 0x26, 0xba, 0x2f, 0xa9, 0x9b, 0x34, 0x51, + 0x70, 0x8a, 0x18, 0x3f, 0x58, 0x12, 0x27, 0xa0, 0xf5, 0x9d, 0xe9, 0x30, 0x14, 0xa7, 0x43, 0xc6, + 0xc1, 0x92, 0x09, 0xc5, 0x19, 0x6c, 0xb4, 0x0c, 0x67, 0x8c, 0x96, 0xeb, 0xc4, 0x6d, 0x6d, 0xac, + 0x05, 0x91, 0xdc, 0x59, 0x3d, 0xa6, 0x03, 0xbb, 0xba, 0x71, 0x70, 0xee, 0x93, 0x54, 0xdb, 0x37, + 0x9c, 0xd0, 0x69, 0xb8, 0xc9, 0x8e, 0xf0, 0x43, 0x2a, 0xd9, 0x34, 0x23, 0xda, 0xb1, 0xc2, 0xb0, + 0x17, 0x61, 0xa0, 0xcf, 0x19, 0xd4, 0x97, 0x45, 0xff, 0x32, 0x54, 0x29, 0x39, 0x69, 0xde, 0x15, + 0x41, 0x32, 0x80, 0xaa, 0xbc, 0xbb, 0x04, 0xd9, 0x50, 0x76, 0x1d, 0x79, 0x76, 0xa7, 0x5e, 0x6b, + 0x3e, 0x8e, 0x3b, 0x6c, 0x93, 0x4c, 0x81, 0xe8, 0x49, 0x28, 0x93, 0xed, 0x30, 0x7b, 0x48, 0x77, + 0x69, 0x3b, 0x74, 0x23, 0x12, 0x53, 0x24, 0xb2, 0x1d, 0xa2, 0xf3, 0x50, 0x72, 0x9b, 0x42, 0x49, + 0x81, 0xc0, 0x29, 0xcd, 0xcf, 0xe2, 0x92, 0xdb, 0xb4, 0xb7, 0xa1, 0xa6, 0x2e, 0x4b, 0x41, 0x9b, + 0x52, 0x76, 0x5b, 0x45, 0x84, 0x3c, 0x49, 0xba, 0x3d, 0xa4, 0x76, 0x07, 0x40, 0xa7, 0x10, 0x16, + 0x25, 0x5f, 0x2e, 0xc0, 0x40, 0x23, 0x10, 0xe9, 0xcd, 0x55, 0x4d, 0x86, 0x09, 0x6d, 0x06, 0xb1, + 0x6f, 0xc1, 0xd8, 0x35, 0x3f, 0xb8, 0xc3, 0x2a, 0xbd, 0xb3, 0xc2, 0x66, 0x94, 0xf0, 0x3a, 0xfd, + 0x91, 0x35, 0x11, 0x18, 0x14, 0x73, 0x98, 0xaa, 0xf8, 0x54, 0xea, 0x55, 0xf1, 0xc9, 0xfe, 0xb8, + 0x05, 0x23, 0x2a, 0x17, 0x69, 0x6e, 0x6b, 0x93, 0xd2, 0x6d, 0x45, 0x41, 0x27, 0xcc, 0xd2, 0x65, + 0xd7, 0x19, 0x61, 0x0e, 0x33, 0x93, 0xf4, 0x4a, 0xfb, 0x24, 0xe9, 0x5d, 0x80, 0x81, 0x4d, 0xd7, + 0x6f, 0x66, 0xef, 0xe7, 0xb8, 0xe6, 0xfa, 0x4d, 0xcc, 0x20, 0xb4, 0x0b, 0x27, 0x55, 0x17, 0xa4, + 0x42, 0x78, 0x11, 0x46, 0xd6, 0x3a, 0xae, 0xd7, 0x94, 0x15, 0xdb, 0x32, 0x9e, 0x92, 0xba, 0x01, + 0xc3, 0x29, 0x4c, 0xba, 0xaf, 0x5b, 0x73, 0x7d, 0x27, 0xda, 0x59, 0xd6, 0x1a, 0x48, 0x09, 0xa5, + 0xba, 0x82, 0x60, 0x03, 0xcb, 0x7e, 0xb3, 0x0c, 0x63, 0xe9, 0x8c, 0xac, 0x3e, 0xb6, 0x57, 0x4f, + 0x42, 0x85, 0x25, 0x69, 0x65, 0x3f, 0x2d, 0x2f, 0x72, 0xc6, 0x61, 0x28, 0x86, 0x41, 0x5e, 0xde, + 0xa1, 0x98, 0xbb, 0x6d, 0x54, 0x27, 0x95, 0x7f, 0x85, 0xc5, 0x93, 0x89, 0x8a, 0x12, 0x82, 0x15, + 0xfa, 0x94, 0x05, 0x43, 0x41, 0x68, 0x56, 0x0a, 0xfa, 0x40, 0x91, 0xd9, 0x6a, 0x22, 0x59, 0x46, + 0x58, 0xc4, 0xea, 0xd3, 0xcb, 0xcf, 0x21, 0x59, 0x9f, 0xff, 0x11, 0x18, 0x31, 0x31, 0xf7, 0x33, + 0x8a, 0xab, 0xa6, 0x51, 0xfc, 0x19, 0x73, 0x52, 0x88, 0x7c, 0xbc, 0x3e, 0x96, 0xdb, 0x0d, 0xa8, + 0x34, 0x54, 0x00, 0xc0, 0xa1, 0xea, 0x7c, 0xaa, 0x7a, 0x0b, 0xec, 0x10, 0x88, 0x53, 0xb3, 0xbf, + 0x65, 0x19, 0xf3, 0x03, 0x93, 0x78, 0xbe, 0x89, 0x22, 0x28, 0xb7, 0xb6, 0x36, 0x85, 0x29, 0x7a, + 0xb5, 0xa0, 0xe1, 0x9d, 0xdb, 0xda, 0xd4, 0x73, 0xdc, 0x6c, 0xc5, 0x94, 0x59, 0x1f, 0x4e, 0xc0, + 0x54, 0xda, 0x66, 0x79, 0xff, 0xb4, 0x4d, 0xfb, 0xad, 0x12, 0x9c, 0xea, 0x9a, 0x54, 0xe8, 0x0d, + 0xa8, 0x44, 0xf4, 0x2d, 0xc5, 0xeb, 0x2d, 0x14, 0x96, 0x68, 0x19, 0xcf, 0x37, 0xb5, 0xde, 0x4d, + 0xb7, 0x63, 0xce, 0x12, 0x5d, 0x05, 0xa4, 0xc3, 0x54, 0x94, 0x07, 0x92, 0xbf, 0xf2, 0x79, 0xf1, + 0x28, 0x9a, 0xee, 0xc2, 0xc0, 0x39, 0x4f, 0xa1, 0x97, 0xb2, 0x8e, 0xcc, 0x72, 0xfa, 0xdc, 0x72, + 0x2f, 0x9f, 0xa4, 0xfd, 0xcf, 0x4b, 0x30, 0x9a, 0x2a, 0xdc, 0x84, 0x3c, 0xa8, 0x12, 0x8f, 0x39, + 0xf5, 0xa5, 0xb2, 0x39, 0x6a, 0x1d, 0x64, 0xa5, 0x20, 0x2f, 0x09, 0xba, 0x58, 0x71, 0x78, 0x38, + 0x0e, 0xd7, 0x5f, 0x84, 0x11, 0xd9, 0xa1, 0x0f, 0x38, 0x6d, 0x4f, 0x0c, 0xa0, 0x9a, 0xa3, 0x97, + 0x0c, 0x18, 0x4e, 0x61, 0xda, 0xbf, 0x53, 0x86, 0x71, 0x7e, 0x0a, 0xd2, 0x54, 0x33, 0x6f, 0x51, + 0xee, 0xb7, 0xfe, 0x8a, 0x2e, 0xaf, 0xc6, 0x07, 0x72, 0xed, 0xa8, 0xd7, 0x0e, 0xe4, 0x33, 0xea, + 0x2b, 0x32, 0xeb, 0x2b, 0x99, 0xc8, 0x2c, 0x6e, 0x76, 0xb7, 0x8e, 0xa9, 0x47, 0xdf, 0x5d, 0xa1, + 0x5a, 0x7f, 0xb7, 0x04, 0x27, 0x32, 0x77, 0x3a, 0xa0, 0x37, 0xd3, 0x65, 0x80, 0xad, 0x22, 0x7c, + 0xe5, 0x7b, 0x96, 0xf9, 0x3f, 0x58, 0x31, 0xe0, 0x07, 0xb4, 0x54, 0xec, 0x3f, 0x28, 0xc1, 0x58, + 0xfa, 0x32, 0x8a, 0x87, 0x70, 0xa4, 0xde, 0x0d, 0x35, 0x56, 0x6f, 0x9d, 0x5d, 0xb2, 0xc9, 0x5d, + 0xf2, 0xbc, 0xb4, 0xb5, 0x6c, 0xc4, 0x1a, 0xfe, 0x50, 0xd4, 0x58, 0xb6, 0xff, 0x9e, 0x05, 0x67, + 0xf9, 0x5b, 0x66, 0xe7, 0xe1, 0x5f, 0xcd, 0x1b, 0xdd, 0x57, 0x8b, 0xed, 0x60, 0xa6, 0x2c, 0xe0, + 0x7e, 0xe3, 0xcb, 0x2e, 0xf7, 0x13, 0xbd, 0x4d, 0x4f, 0x85, 0x87, 0xb0, 0xb3, 0x07, 0x9a, 0x0c, + 0xf6, 0x1f, 0x94, 0x41, 0xdf, 0x67, 0x88, 0x5c, 0x91, 0xe3, 0x58, 0x48, 0x79, 0xc4, 0x95, 0x1d, + 0xbf, 0xa1, 0x6f, 0x4e, 0xac, 0x66, 0x52, 0x1c, 0x7f, 0xce, 0x82, 0x61, 0xd7, 0x77, 0x13, 0xd7, + 0x61, 0xdb, 0xe8, 0x62, 0xee, 0x5a, 0x53, 0xec, 0xe6, 0x39, 0xe5, 0x20, 0x32, 0xcf, 0x71, 0x14, + 0x33, 0x6c, 0x72, 0x46, 0x1f, 0x16, 0xc1, 0xd3, 0xe5, 0xc2, 0xb2, 0x73, 0xab, 0x99, 0x88, 0xe9, + 0x90, 0x1a, 0x5e, 0x49, 0x54, 0x50, 0x52, 0x3b, 0xa6, 0xa4, 0x54, 0xa5, 0x5d, 0x7d, 0xb3, 0x34, + 0x6d, 0xc6, 0x9c, 0x91, 0x1d, 0x03, 0xea, 0x1e, 0x8b, 0x03, 0x06, 0xa6, 0x4e, 0x41, 0xcd, 0xe9, + 0x24, 0x41, 0x9b, 0x0e, 0x93, 0x38, 0x6a, 0xd2, 0xa1, 0xb7, 0x12, 0x80, 0x35, 0x8e, 0xfd, 0x66, + 0x05, 0x32, 0x49, 0x87, 0x68, 0xdb, 0xbc, 0x8b, 0xd3, 0x2a, 0xf6, 0x2e, 0x4e, 0xd5, 0x99, 0xbc, + 0xfb, 0x38, 0x51, 0x0b, 0x2a, 0xe1, 0x86, 0x13, 0x4b, 0xb3, 0xfa, 0x65, 0xb5, 0x8f, 0xa3, 0x8d, + 0xf7, 0x76, 0x27, 0x7e, 0xbc, 0x3f, 0xaf, 0x2b, 0x9d, 0xab, 0x53, 0xbc, 0x7c, 0x89, 0x66, 0xcd, + 0x68, 0x60, 0x4e, 0xff, 0x20, 0xb7, 0xcd, 0x7d, 0x42, 0x14, 0x96, 0xc7, 0x24, 0xee, 0x78, 0x89, + 0x98, 0x0d, 0x2f, 0x17, 0xb8, 0xca, 0x38, 0x61, 0x9d, 0x2e, 0xcf, 0xff, 0x63, 0x83, 0x29, 0xfa, + 0x20, 0xd4, 0xe2, 0xc4, 0x89, 0x92, 0x43, 0x26, 0xb8, 0xaa, 0x41, 0x5f, 0x91, 0x44, 0xb0, 0xa6, + 0x87, 0x5e, 0x61, 0xd5, 0x62, 0xdd, 0x78, 0xe3, 0x90, 0x39, 0x0f, 0xb2, 0xb2, 0xac, 0xa0, 0x80, + 0x0d, 0x6a, 0xe8, 0x22, 0x00, 0x9b, 0xdb, 0x3c, 0xd0, 0xaf, 0xca, 0xbc, 0x4c, 0x4a, 0x14, 0x62, + 0x05, 0xc1, 0x06, 0x96, 0xfd, 0x83, 0x90, 0xae, 0xf7, 0x80, 0x26, 0x64, 0x79, 0x09, 0xee, 0x85, + 0x66, 0xb9, 0x0b, 0xa9, 0x4a, 0x10, 0xbf, 0x6e, 0x81, 0x59, 0x94, 0x02, 0xbd, 0xce, 0xab, 0x5f, + 0x58, 0x45, 0x9c, 0x1c, 0x1a, 0x74, 0x27, 0x17, 0x9d, 0x30, 0x73, 0x84, 0x2d, 0x4b, 0x60, 0x9c, + 0x7f, 0x0f, 0x54, 0x25, 0xf4, 0x40, 0x46, 0xdd, 0xc7, 0xe0, 0x74, 0xf6, 0xa6, 0x72, 0x71, 0xea, + 0xb4, 0xbf, 0xeb, 0x47, 0xfa, 0x73, 0x4a, 0xbd, 0xfc, 0x39, 0x7d, 0xdc, 0xc8, 0xfa, 0x1b, 0x16, + 0x5c, 0xd8, 0xef, 0x42, 0x75, 0xf4, 0x18, 0x0c, 0xdc, 0x71, 0x22, 0x59, 0xc6, 0x9b, 0x09, 0xca, + 0x5b, 0x4e, 0xe4, 0x63, 0xd6, 0x8a, 0x76, 0x60, 0x90, 0x47, 0x83, 0x09, 0x6b, 0xfd, 0xe5, 0x62, + 0xaf, 0x77, 0xbf, 0x46, 0x8c, 0xed, 0x02, 0x8f, 0x44, 0xc3, 0x82, 0xa1, 0xfd, 0x6d, 0x0b, 0xd0, + 0xd2, 0x16, 0x89, 0x22, 0xb7, 0x69, 0xc4, 0xaf, 0xb1, 0x0b, 0x5a, 0x8c, 0x8b, 0x58, 0xcc, 0x14, + 0xd7, 0xcc, 0x05, 0x2d, 0xc6, 0xbf, 0xfc, 0x0b, 0x5a, 0x4a, 0x07, 0xbb, 0xa0, 0x05, 0x2d, 0xc1, + 0xd9, 0x36, 0xdf, 0x6e, 0xf0, 0x4b, 0x0f, 0xf8, 0xde, 0x43, 0x25, 0x94, 0x9d, 0xbb, 0xbb, 0x3b, + 0x71, 0x76, 0x31, 0x0f, 0x01, 0xe7, 0x3f, 0x67, 0xbf, 0x07, 0x10, 0x0f, 0x5b, 0x9b, 0xc9, 0x8b, + 0x41, 0xea, 0xe9, 0x7e, 0xb1, 0xbf, 0x5c, 0x81, 0x13, 0x99, 0x22, 0xaf, 0x74, 0xab, 0xd7, 0x1d, + 0xf4, 0x74, 0x64, 0xfd, 0xdd, 0xdd, 0xbd, 0xbe, 0xc2, 0xa8, 0x7c, 0xa8, 0xb8, 0x7e, 0xd8, 0x49, + 0x8a, 0xc9, 0x21, 0xe5, 0x9d, 0x98, 0xa7, 0x04, 0x0d, 0x77, 0x31, 0xfd, 0x8b, 0x39, 0x9b, 0x22, + 0x83, 0xb2, 0x52, 0xc6, 0xf8, 0xc0, 0x03, 0x72, 0x07, 0x7c, 0x42, 0x87, 0x48, 0x55, 0x8a, 0x70, + 0x2c, 0x66, 0x26, 0xcb, 0x71, 0x1f, 0xb5, 0xff, 0x5a, 0x09, 0x86, 0x8d, 0x8f, 0x86, 0x7e, 0x29, + 0x5d, 0xb2, 0xc9, 0x2a, 0xee, 0x95, 0x18, 0xfd, 0x49, 0x5d, 0x94, 0x89, 0xbf, 0xd2, 0x53, 0xdd, + 0xd5, 0x9a, 0xee, 0xed, 0x4e, 0x9c, 0xcc, 0xd4, 0x63, 0x4a, 0x55, 0x70, 0x3a, 0xff, 0x51, 0x38, + 0x91, 0x21, 0x93, 0xf3, 0xca, 0xab, 0xe9, 0x8b, 0xe8, 0x8f, 0xe8, 0x96, 0x32, 0x87, 0xec, 0xeb, + 0x74, 0xc8, 0x44, 0x1a, 0x5d, 0xe0, 0x91, 0x3e, 0x7c, 0xb0, 0x99, 0x6c, 0xd9, 0x52, 0x9f, 0xd9, + 0xb2, 0x4f, 0x43, 0x35, 0x0c, 0x3c, 0xb7, 0xe1, 0xaa, 0xba, 0x86, 0x2c, 0x3f, 0x77, 0x59, 0xb4, + 0x61, 0x05, 0x45, 0x77, 0xa0, 0xa6, 0xee, 0xec, 0x17, 0xfe, 0xed, 0xa2, 0x0e, 0x7d, 0x94, 0xd1, + 0xa2, 0xef, 0xe2, 0xd7, 0xbc, 0x90, 0x0d, 0x83, 0x4c, 0x09, 0xca, 0xd0, 0x7f, 0xe6, 0x7b, 0x67, + 0xda, 0x31, 0xc6, 0x02, 0x62, 0x7f, 0xad, 0x06, 0x67, 0xf2, 0x2a, 0x6d, 0xa3, 0x8f, 0xc0, 0x20, + 0xef, 0x63, 0x31, 0x97, 0x39, 0xe4, 0xf1, 0x98, 0x63, 0x04, 0x45, 0xb7, 0xd8, 0x6f, 0x2c, 0x78, + 0x0a, 0xee, 0x9e, 0xb3, 0x26, 0x66, 0xc8, 0xf1, 0x70, 0x5f, 0x70, 0x34, 0xf7, 0x05, 0x87, 0x73, + 0xf7, 0x9c, 0x35, 0xb4, 0x0d, 0x95, 0x96, 0x9b, 0x10, 0x47, 0x38, 0x11, 0x6e, 0x1d, 0x0b, 0x73, + 0xe2, 0x70, 0x2b, 0x8d, 0xfd, 0xc4, 0x9c, 0x21, 0xfa, 0xaa, 0x05, 0x27, 0xd6, 0xd2, 0xa9, 0xf1, + 0x42, 0x78, 0x3a, 0xc7, 0x50, 0x4d, 0x3d, 0xcd, 0x88, 0xdf, 0x50, 0x94, 0x69, 0xc4, 0xd9, 0xee, + 0xa0, 0x4f, 0x5a, 0x30, 0xb4, 0xee, 0x7a, 0x46, 0x61, 0xdd, 0x63, 0xf8, 0x38, 0x97, 0x19, 0x03, + 0xbd, 0xe3, 0xe0, 0xff, 0x63, 0x2c, 0x39, 0xf7, 0xd2, 0x54, 0x83, 0x47, 0xd5, 0x54, 0x43, 0x0f, + 0x48, 0x53, 0x7d, 0xda, 0x82, 0x9a, 0x1a, 0x69, 0x91, 0xee, 0xfc, 0xc1, 0x63, 0xfc, 0xe4, 0xdc, + 0x73, 0xa2, 0xfe, 0x62, 0xcd, 0x1c, 0x7d, 0xc1, 0x82, 0x61, 0xe7, 0x8d, 0x4e, 0x44, 0x9a, 0x64, + 0x2b, 0x08, 0x63, 0x71, 0xbd, 0xe1, 0xab, 0xc5, 0x77, 0x66, 0x9a, 0x32, 0x99, 0x25, 0x5b, 0x4b, + 0x61, 0x2c, 0xd2, 0x92, 0x74, 0x03, 0x36, 0xbb, 0x60, 0xef, 0x96, 0x60, 0x62, 0x1f, 0x0a, 0xe8, + 0x45, 0x18, 0x09, 0xa2, 0x96, 0xe3, 0xbb, 0x6f, 0x98, 0xb5, 0x2e, 0x94, 0x95, 0xb5, 0x64, 0xc0, + 0x70, 0x0a, 0xd3, 0x4c, 0xc8, 0x2e, 0xed, 0x93, 0x90, 0x7d, 0x01, 0x06, 0x22, 0x12, 0x06, 0xd9, + 0xcd, 0x02, 0x4b, 0x09, 0x60, 0x10, 0xf4, 0x38, 0x94, 0x9d, 0xd0, 0x15, 0x81, 0x68, 0x6a, 0x0f, + 0x34, 0xbd, 0x3c, 0x8f, 0x69, 0x7b, 0xaa, 0x3e, 0x44, 0xe5, 0xbe, 0xd4, 0x87, 0xa0, 0x6a, 0x40, + 0x9c, 0x5d, 0x0c, 0x6a, 0x35, 0x90, 0x3e, 0x53, 0xb0, 0xdf, 0x2a, 0xc3, 0xe3, 0x7b, 0xce, 0x17, + 0x1d, 0x87, 0x67, 0xed, 0x11, 0x87, 0x27, 0x87, 0xa7, 0xb4, 0xdf, 0xf0, 0x94, 0x7b, 0x0c, 0xcf, + 0x27, 0xe9, 0x32, 0x90, 0x35, 0x42, 0x8a, 0xb9, 0xa0, 0xae, 0x57, 0xc9, 0x11, 0xb1, 0x02, 0x24, + 0x14, 0x6b, 0xbe, 0x74, 0x0f, 0x90, 0x4a, 0x46, 0xae, 0x14, 0xa1, 0x06, 0x7a, 0xd6, 0x0c, 0xe1, + 0x73, 0xbf, 0x57, 0x86, 0xb3, 0xfd, 0xf3, 0x25, 0x78, 0xb2, 0x0f, 0xe9, 0x6d, 0xce, 0x62, 0xab, + 0xcf, 0x59, 0xfc, 0xdd, 0xfd, 0x99, 0xec, 0xbf, 0x66, 0xc1, 0xf9, 0xde, 0xca, 0x03, 0x3d, 0x07, + 0xc3, 0x6b, 0x91, 0xe3, 0x37, 0x36, 0xd8, 0xa5, 0x9b, 0x72, 0x50, 0xd8, 0x58, 0xeb, 0x66, 0x6c, + 0xe2, 0xd0, 0xed, 0x2d, 0x8f, 0x49, 0x30, 0x30, 0x64, 0xf2, 0x28, 0xdd, 0xde, 0xae, 0x66, 0x81, + 0xb8, 0x1b, 0xdf, 0xfe, 0xb3, 0x52, 0x7e, 0xb7, 0xb8, 0x91, 0x71, 0x90, 0xef, 0x24, 0xbe, 0x42, + 0xa9, 0x0f, 0x59, 0x52, 0xbe, 0xdf, 0xb2, 0x64, 0xa0, 0x97, 0x2c, 0x41, 0xb3, 0x70, 0xd2, 0xb8, + 0x94, 0x85, 0x27, 0x04, 0xf3, 0x80, 0x5b, 0x55, 0x25, 0x63, 0x39, 0x03, 0xc7, 0x5d, 0x4f, 0xa0, + 0x67, 0xa0, 0xea, 0xfa, 0x31, 0x69, 0x74, 0x22, 0x1e, 0xe8, 0x6d, 0x24, 0x61, 0xcd, 0x8b, 0x76, + 0xac, 0x30, 0xec, 0x5f, 0x2e, 0xc1, 0xb9, 0x9e, 0x76, 0xd6, 0x7d, 0x92, 0x5d, 0xe6, 0xe7, 0x18, + 0xb8, 0x3f, 0x9f, 0xc3, 0x1c, 0xa4, 0xca, 0xbe, 0x83, 0xf4, 0x87, 0xbd, 0x27, 0x26, 0xb5, 0xb9, + 0xbf, 0x67, 0x47, 0xe9, 0x25, 0x18, 0x75, 0xc2, 0x90, 0xe3, 0xb1, 0x78, 0xcd, 0x4c, 0x95, 0x9c, + 0x69, 0x13, 0x88, 0xd3, 0xb8, 0x7d, 0x69, 0xcf, 0x3f, 0xb6, 0xa0, 0x86, 0xc9, 0x3a, 0x97, 0x0e, + 0xe8, 0xb6, 0x18, 0x22, 0xab, 0x88, 0x7a, 0x9a, 0x74, 0x60, 0x63, 0x97, 0xd5, 0x99, 0xcc, 0x1b, + 0xec, 0xee, 0xcb, 0x7b, 0x4a, 0x07, 0xba, 0xbc, 0x47, 0x5d, 0xdf, 0x52, 0xee, 0x7d, 0x7d, 0x8b, + 0xfd, 0xf5, 0x21, 0xfa, 0x7a, 0x61, 0x30, 0x13, 0x91, 0x66, 0x4c, 0xbf, 0x6f, 0x27, 0xf2, 0xc4, + 0x24, 0x51, 0xdf, 0xf7, 0x06, 0x5e, 0xc0, 0xb4, 0x3d, 0x75, 0x14, 0x53, 0x3a, 0x50, 0x8d, 0x90, + 0xf2, 0xbe, 0x35, 0x42, 0x5e, 0x82, 0xd1, 0x38, 0xde, 0x58, 0x8e, 0xdc, 0x2d, 0x27, 0x21, 0xd7, + 0xc8, 0x8e, 0xb0, 0xb2, 0x74, 0x5e, 0xff, 0xca, 0x15, 0x0d, 0xc4, 0x69, 0x5c, 0x34, 0x07, 0xa7, + 0x74, 0xa5, 0x0e, 0x12, 0x25, 0x2c, 0xba, 0x9f, 0xcf, 0x04, 0x95, 0xc4, 0xab, 0x6b, 0x7b, 0x08, + 0x04, 0xdc, 0xfd, 0x0c, 0x95, 0x6f, 0xa9, 0x46, 0xda, 0x91, 0xc1, 0xb4, 0x7c, 0x4b, 0xd1, 0xa1, + 0x7d, 0xe9, 0x7a, 0x02, 0x2d, 0xc2, 0x69, 0x3e, 0x31, 0xa6, 0xc3, 0xd0, 0x78, 0xa3, 0xa1, 0x74, + 0x1d, 0xc3, 0xb9, 0x6e, 0x14, 0x9c, 0xf7, 0x1c, 0x7a, 0x01, 0x86, 0x55, 0xf3, 0xfc, 0xac, 0x38, + 0x45, 0x50, 0x5e, 0x0c, 0x45, 0x66, 0xbe, 0x89, 0x4d, 0x3c, 0xf4, 0x01, 0x78, 0x54, 0xff, 0xe5, + 0x29, 0x60, 0xfc, 0x68, 0x6d, 0x56, 0x14, 0x41, 0x52, 0x97, 0x85, 0xcc, 0xe5, 0xa2, 0x35, 0x71, + 0xaf, 0xe7, 0xd1, 0x1a, 0x9c, 0x57, 0xa0, 0x4b, 0x7e, 0xc2, 0xf2, 0x39, 0x62, 0x52, 0x77, 0x62, + 0x72, 0x23, 0xf2, 0xc4, 0x6d, 0xab, 0xea, 0x1e, 0xc7, 0x39, 0x37, 0xb9, 0x92, 0x87, 0x89, 0x17, + 0xf0, 0x1e, 0x54, 0xd0, 0x14, 0xd4, 0x88, 0xef, 0xac, 0x79, 0x64, 0x69, 0x66, 0x9e, 0x15, 0x53, + 0x32, 0x4e, 0xf2, 0x2e, 0x49, 0x00, 0xd6, 0x38, 0x2a, 0xc2, 0x74, 0xa4, 0xe7, 0x9d, 0xa2, 0xcb, + 0x70, 0xa6, 0xd5, 0x08, 0xa9, 0xed, 0xe1, 0x36, 0xc8, 0x74, 0x83, 0x05, 0xd4, 0xd1, 0x0f, 0xc3, + 0x0b, 0x4c, 0xaa, 0xf0, 0xe9, 0xb9, 0x99, 0xe5, 0x2e, 0x1c, 0x9c, 0xfb, 0x24, 0x0b, 0xbc, 0x8c, + 0x82, 0xed, 0x9d, 0xf1, 0xd3, 0x99, 0xc0, 0x4b, 0xda, 0x88, 0x39, 0x0c, 0x5d, 0x05, 0xc4, 0x62, + 0xf1, 0xaf, 0x24, 0x49, 0xa8, 0x8c, 0x9d, 0xf1, 0x33, 0xec, 0x95, 0x54, 0x18, 0xd9, 0xe5, 0x2e, + 0x0c, 0x9c, 0xf3, 0x94, 0xfd, 0x1f, 0x2c, 0x18, 0x55, 0xeb, 0xf5, 0x3e, 0x64, 0xa3, 0x78, 0xe9, + 0x6c, 0x94, 0xb9, 0xa3, 0x4b, 0x3c, 0xd6, 0xf3, 0x1e, 0x21, 0xcd, 0x3f, 0x33, 0x0c, 0xa0, 0xa5, + 0xa2, 0x52, 0x48, 0x56, 0x4f, 0x85, 0xf4, 0xd0, 0x4a, 0xa4, 0xbc, 0xca, 0x29, 0x95, 0x07, 0x5b, + 0x39, 0x65, 0x05, 0xce, 0x4a, 0x73, 0x81, 0x9f, 0x15, 0x5d, 0x09, 0x62, 0x25, 0xe0, 0xaa, 0xf5, + 0xc7, 0x05, 0xa1, 0xb3, 0xf3, 0x79, 0x48, 0x38, 0xff, 0xd9, 0x94, 0x95, 0x32, 0xb4, 0x9f, 0x95, + 0xa2, 0xd7, 0xf4, 0xc2, 0xba, 0xbc, 0x15, 0x24, 0xb3, 0xa6, 0x17, 0x2e, 0xaf, 0x60, 0x8d, 0x93, + 0x2f, 0xd8, 0x6b, 0x05, 0x09, 0x76, 0x38, 0xb0, 0x60, 0x97, 0x22, 0x66, 0xb8, 0xa7, 0x88, 0x91, + 0x3e, 0xe9, 0x91, 0x9e, 0x3e, 0xe9, 0xf7, 0xc2, 0x98, 0xeb, 0x6f, 0x90, 0xc8, 0x4d, 0x48, 0x93, + 0xad, 0x05, 0x26, 0x7e, 0xaa, 0x5a, 0xad, 0xcf, 0xa7, 0xa0, 0x38, 0x83, 0x9d, 0x96, 0x8b, 0x63, + 0x7d, 0xc8, 0xc5, 0x1e, 0xda, 0xe8, 0x44, 0x31, 0xda, 0xe8, 0xe4, 0xd1, 0xb5, 0xd1, 0xa9, 0x63, + 0xd5, 0x46, 0xa8, 0x10, 0x6d, 0xd4, 0x97, 0xa0, 0x37, 0xb6, 0x7f, 0x67, 0xf6, 0xd9, 0xfe, 0xf5, + 0x52, 0x45, 0x67, 0x0f, 0xad, 0x8a, 0xf2, 0xb5, 0xcc, 0x23, 0x87, 0xd2, 0x32, 0x9f, 0x2e, 0xc1, + 0x59, 0x2d, 0x87, 0xe9, 0xec, 0x77, 0xd7, 0xa9, 0x24, 0x62, 0x17, 0x4b, 0xf1, 0x73, 0x1b, 0x23, + 0x39, 0x4a, 0xe7, 0x59, 0x29, 0x08, 0x36, 0xb0, 0x58, 0x8e, 0x11, 0x89, 0x58, 0x19, 0xdd, 0xac, + 0x90, 0x9e, 0x11, 0xed, 0x58, 0x61, 0xd0, 0xf9, 0x45, 0x7f, 0x8b, 0xbc, 0xcd, 0x6c, 0xb1, 0xb8, + 0x19, 0x0d, 0xc2, 0x26, 0x1e, 0x7a, 0x9a, 0x33, 0x61, 0x02, 0x82, 0x0a, 0xea, 0x11, 0x71, 0xd3, + 0xac, 0x94, 0x09, 0x0a, 0x2a, 0xbb, 0xc3, 0x92, 0xc9, 0x2a, 0xdd, 0xdd, 0x61, 0x21, 0x50, 0x0a, + 0xc3, 0xfe, 0x9f, 0x16, 0x9c, 0xcb, 0x1d, 0x8a, 0xfb, 0xa0, 0x7c, 0xb7, 0xd3, 0xca, 0x77, 0xa5, + 0xa8, 0xed, 0x86, 0xf1, 0x16, 0x3d, 0x14, 0xf1, 0xbf, 0xb3, 0x60, 0x4c, 0xe3, 0xdf, 0x87, 0x57, + 0x75, 0xd3, 0xaf, 0x5a, 0xdc, 0xce, 0xaa, 0xd6, 0xf5, 0x6e, 0xbf, 0x53, 0x02, 0x55, 0xc0, 0x71, + 0xba, 0x21, 0xcb, 0xe3, 0xee, 0x73, 0x92, 0xb8, 0x03, 0x83, 0xec, 0x20, 0x34, 0x2e, 0x26, 0xc8, + 0x23, 0xcd, 0x9f, 0x1d, 0xaa, 0xea, 0x43, 0x66, 0xf6, 0x37, 0xc6, 0x82, 0x21, 0x2b, 0xf2, 0xec, + 0xc6, 0x54, 0x9a, 0x37, 0x45, 0x5a, 0x96, 0x2e, 0xf2, 0x2c, 0xda, 0xb1, 0xc2, 0xa0, 0xea, 0xc1, + 0x6d, 0x04, 0xfe, 0x8c, 0xe7, 0xc4, 0xf2, 0x36, 0x45, 0xa5, 0x1e, 0xe6, 0x25, 0x00, 0x6b, 0x1c, + 0x76, 0x46, 0xea, 0xc6, 0xa1, 0xe7, 0xec, 0x18, 0xfb, 0x67, 0xa3, 0x3e, 0x81, 0x02, 0x61, 0x13, + 0xcf, 0x6e, 0xc3, 0x78, 0xfa, 0x25, 0x66, 0xc9, 0x3a, 0x0b, 0x50, 0xec, 0x6b, 0x38, 0xa7, 0xa0, + 0xe6, 0xb0, 0xa7, 0x16, 0x3a, 0x4e, 0xf6, 0x12, 0xf4, 0x69, 0x09, 0xc0, 0x1a, 0xc7, 0xfe, 0x55, + 0x0b, 0x4e, 0xe7, 0x0c, 0x5a, 0x81, 0x69, 0x6f, 0x89, 0x96, 0x36, 0x79, 0x8a, 0xfd, 0x07, 0x60, + 0xa8, 0x49, 0xd6, 0x1d, 0x19, 0x02, 0x67, 0xc8, 0xf6, 0x59, 0xde, 0x8c, 0x25, 0xdc, 0xfe, 0xef, + 0x16, 0x9c, 0x48, 0xf7, 0x35, 0x66, 0xa9, 0x24, 0x7c, 0x98, 0xdc, 0xb8, 0x11, 0x6c, 0x91, 0x68, + 0x87, 0xbe, 0xb9, 0x95, 0x49, 0x25, 0xe9, 0xc2, 0xc0, 0x39, 0x4f, 0xb1, 0xf2, 0xad, 0x4d, 0x35, + 0xda, 0x72, 0x46, 0xde, 0x2c, 0x72, 0x46, 0xea, 0x8f, 0x69, 0x1e, 0x97, 0x2b, 0x96, 0xd8, 0xe4, + 0x6f, 0x7f, 0x7b, 0x00, 0x54, 0x5e, 0x2c, 0x8b, 0x3f, 0x2a, 0x28, 0x7a, 0xeb, 0xa0, 0x19, 0x44, + 0x6a, 0x32, 0x0c, 0xec, 0x15, 0x10, 0xc0, 0xbd, 0x24, 0xa6, 0xeb, 0x52, 0xbd, 0xe1, 0xaa, 0x06, + 0x61, 0x13, 0x8f, 0xf6, 0xc4, 0x73, 0xb7, 0x08, 0x7f, 0x68, 0x30, 0xdd, 0x93, 0x05, 0x09, 0xc0, + 0x1a, 0x87, 0xf6, 0xa4, 0xe9, 0xae, 0xaf, 0x8b, 0x2d, 0xbf, 0xea, 0x09, 0x1d, 0x1d, 0xcc, 0x20, + 0xbc, 0x22, 0x77, 0xb0, 0x29, 0xac, 0x60, 0xa3, 0x22, 0x77, 0xb0, 0x89, 0x19, 0x84, 0xda, 0x6d, + 0x7e, 0x10, 0xb5, 0xd9, 0x25, 0xf5, 0x4d, 0xc5, 0x45, 0x58, 0xbf, 0xca, 0x6e, 0xbb, 0xde, 0x8d, + 0x82, 0xf3, 0x9e, 0xa3, 0x33, 0x30, 0x8c, 0x48, 0xd3, 0x6d, 0x24, 0x26, 0x35, 0x48, 0xcf, 0xc0, + 0xe5, 0x2e, 0x0c, 0x9c, 0xf3, 0x14, 0x9a, 0x86, 0x13, 0x32, 0xaf, 0x59, 0x56, 0xad, 0x19, 0x4e, + 0x57, 0xc9, 0xc0, 0x69, 0x30, 0xce, 0xe2, 0x53, 0xa9, 0xd6, 0x16, 0x05, 0xab, 0x98, 0xb1, 0x6c, + 0x48, 0x35, 0x59, 0xc8, 0x0a, 0x2b, 0x0c, 0xfb, 0x13, 0x65, 0xaa, 0x85, 0x7b, 0x14, 0x6a, 0xbb, + 0x6f, 0xd1, 0x82, 0xe9, 0x19, 0x39, 0xd0, 0xc7, 0x8c, 0x7c, 0x1e, 0x46, 0x6e, 0xc7, 0x81, 0xaf, + 0x22, 0xf1, 0x2a, 0x3d, 0x23, 0xf1, 0x0c, 0xac, 0xfc, 0x48, 0xbc, 0xc1, 0xa2, 0x22, 0xf1, 0x86, + 0x0e, 0x19, 0x89, 0xf7, 0xcd, 0x0a, 0xa8, 0xab, 0x41, 0xae, 0x93, 0xe4, 0x4e, 0x10, 0x6d, 0xba, + 0x7e, 0x8b, 0xe5, 0x83, 0x7f, 0xd5, 0x82, 0x11, 0xbe, 0x5e, 0x16, 0xcc, 0x4c, 0xaa, 0xf5, 0x82, + 0xee, 0x9c, 0x48, 0x31, 0x9b, 0x5c, 0x35, 0x18, 0x65, 0x2e, 0xf3, 0x34, 0x41, 0x38, 0xd5, 0x23, + 0xf4, 0x51, 0x00, 0xe9, 0x1f, 0x5d, 0x97, 0x22, 0x73, 0xbe, 0x98, 0xfe, 0x61, 0xb2, 0xae, 0x6d, + 0xe0, 0x55, 0xc5, 0x04, 0x1b, 0x0c, 0xd1, 0xa7, 0x75, 0x96, 0x19, 0x0f, 0xd9, 0xff, 0xf0, 0xb1, + 0x8c, 0x4d, 0x3f, 0x39, 0x66, 0x18, 0x86, 0x5c, 0xbf, 0x45, 0xe7, 0x89, 0x88, 0x58, 0x7a, 0x57, + 0x5e, 0x2d, 0x85, 0x85, 0xc0, 0x69, 0xd6, 0x1d, 0xcf, 0xf1, 0x1b, 0x24, 0x9a, 0xe7, 0xe8, 0xe6, + 0x15, 0xd6, 0xac, 0x01, 0x4b, 0x42, 0x5d, 0x97, 0xaa, 0x54, 0xfa, 0xb9, 0x54, 0xe5, 0xfc, 0xfb, + 0xe0, 0x54, 0xd7, 0xc7, 0x3c, 0x50, 0x4a, 0xd9, 0xe1, 0xb3, 0xd1, 0xec, 0x7f, 0x31, 0xa8, 0x95, + 0xd6, 0xf5, 0xa0, 0xc9, 0xaf, 0xf6, 0x88, 0xf4, 0x17, 0x15, 0x36, 0x6e, 0x81, 0x53, 0xc4, 0xb8, + 0x06, 0x5b, 0x35, 0x62, 0x93, 0x25, 0x9d, 0xa3, 0xa1, 0x13, 0x11, 0xff, 0xb8, 0xe7, 0xe8, 0xb2, + 0x62, 0x82, 0x0d, 0x86, 0x68, 0x23, 0x95, 0x53, 0x72, 0xf9, 0xe8, 0x39, 0x25, 0xac, 0xca, 0x54, + 0x5e, 0x35, 0xfe, 0x2f, 0x58, 0x30, 0xe6, 0xa7, 0x66, 0x6e, 0x31, 0x61, 0xa4, 0xf9, 0xab, 0x82, + 0xdf, 0x2c, 0x95, 0x6e, 0xc3, 0x19, 0xfe, 0x79, 0x2a, 0xad, 0x72, 0x40, 0x95, 0xa6, 0xef, 0x08, + 0x1a, 0xec, 0x75, 0x47, 0x10, 0xf2, 0xd5, 0x25, 0x69, 0x43, 0x85, 0x5f, 0x92, 0x06, 0x39, 0x17, + 0xa4, 0xdd, 0x82, 0x5a, 0x23, 0x22, 0x4e, 0x72, 0xc8, 0xfb, 0xb2, 0xd8, 0x01, 0xfd, 0x8c, 0x24, + 0x80, 0x35, 0x2d, 0xfb, 0xff, 0x0c, 0xc0, 0x49, 0x39, 0x22, 0x32, 0x04, 0x9d, 0xea, 0x47, 0xce, + 0x57, 0x1b, 0xb7, 0x4a, 0x3f, 0x5e, 0x91, 0x00, 0xac, 0x71, 0xa8, 0x3d, 0xd6, 0x89, 0xc9, 0x52, + 0x48, 0xfc, 0x05, 0x77, 0x2d, 0x16, 0xe7, 0x9c, 0x6a, 0xa1, 0xdc, 0xd0, 0x20, 0x6c, 0xe2, 0x51, + 0x63, 0x9c, 0xdb, 0xc5, 0x71, 0x36, 0x7d, 0x45, 0xd8, 0xdb, 0x58, 0xc2, 0xd1, 0x2f, 0xe4, 0x56, + 0x8e, 0x2d, 0x26, 0x71, 0xab, 0x2b, 0xf2, 0xfe, 0x80, 0x57, 0x2c, 0xfe, 0x6d, 0x0b, 0xce, 0xf2, + 0x56, 0x39, 0x92, 0x37, 0xc2, 0xa6, 0x93, 0x90, 0xb8, 0x98, 0x4a, 0xee, 0x39, 0xfd, 0xd3, 0x4e, + 0xde, 0x3c, 0xb6, 0x38, 0xbf, 0x37, 0xe8, 0x4d, 0x0b, 0x4e, 0x6c, 0xa6, 0x6a, 0x7e, 0x48, 0xd5, + 0x71, 0xd4, 0x74, 0xfc, 0x14, 0x51, 0xbd, 0xd4, 0xd2, 0xed, 0x31, 0xce, 0x72, 0xb7, 0xff, 0xcc, + 0x02, 0x53, 0x8c, 0xde, 0xff, 0x52, 0x21, 0x07, 0x37, 0x05, 0xa5, 0x75, 0x59, 0xe9, 0x69, 0x5d, + 0x3e, 0x0e, 0xe5, 0x8e, 0xdb, 0x14, 0xfb, 0x0b, 0x7d, 0xfa, 0x3a, 0x3f, 0x8b, 0x69, 0xbb, 0xfd, + 0x4f, 0x2b, 0xda, 0x6f, 0x21, 0xf2, 0xa2, 0xbe, 0x27, 0x5e, 0x7b, 0x5d, 0x15, 0x1b, 0xe3, 0x6f, + 0x7e, 0xbd, 0xab, 0xd8, 0xd8, 0x8f, 0x1e, 0x3c, 0xed, 0x8d, 0x0f, 0x50, 0xaf, 0x5a, 0x63, 0x43, + 0xfb, 0xe4, 0xbc, 0xdd, 0x86, 0x2a, 0xdd, 0x82, 0x31, 0x07, 0x64, 0x35, 0xd5, 0xa9, 0xea, 0x15, + 0xd1, 0x7e, 0x6f, 0x77, 0xe2, 0x47, 0x0e, 0xde, 0x2d, 0xf9, 0x34, 0x56, 0xf4, 0x51, 0x0c, 0x35, + 0xfa, 0x9b, 0xa5, 0xe7, 0x89, 0xcd, 0xdd, 0x0d, 0x25, 0x33, 0x25, 0xa0, 0x90, 0xdc, 0x3f, 0xcd, + 0x07, 0xf9, 0x50, 0x63, 0xb7, 0xd1, 0x32, 0xa6, 0x7c, 0x0f, 0xb8, 0xac, 0x92, 0xe4, 0x24, 0xe0, + 0xde, 0xee, 0xc4, 0x4b, 0x07, 0x67, 0xaa, 0x1e, 0xc7, 0x9a, 0x85, 0xfd, 0xc5, 0x01, 0x3d, 0x77, + 0x45, 0x8d, 0xb9, 0xef, 0x89, 0xb9, 0xfb, 0x62, 0x66, 0xee, 0x5e, 0xe8, 0x9a, 0xbb, 0x63, 0xfa, + 0xd6, 0xd4, 0xd4, 0x6c, 0xbc, 0xdf, 0x86, 0xc0, 0xfe, 0xfe, 0x06, 0x66, 0x01, 0xbd, 0xde, 0x71, + 0x23, 0x12, 0x2f, 0x47, 0x1d, 0xdf, 0xf5, 0x5b, 0x6c, 0x3a, 0x56, 0x4d, 0x0b, 0x28, 0x05, 0xc6, + 0x59, 0x7c, 0xba, 0xa9, 0xa7, 0xdf, 0xfc, 0x96, 0xb3, 0xc5, 0x67, 0x95, 0x51, 0x76, 0x6b, 0x45, + 0xb4, 0x63, 0x85, 0x61, 0x7f, 0x9d, 0x9d, 0x65, 0x1b, 0x79, 0xc1, 0x74, 0x4e, 0x78, 0xec, 0xfa, + 0x5f, 0x5e, 0xb3, 0x4b, 0xcd, 0x09, 0x7e, 0xe7, 0x2f, 0x87, 0xa1, 0x3b, 0x30, 0xb4, 0xc6, 0xef, + 0xbf, 0x2b, 0xa6, 0x3e, 0xb9, 0xb8, 0x4c, 0x8f, 0xdd, 0x72, 0x22, 0x6f, 0xd6, 0xbb, 0xa7, 0x7f, + 0x62, 0xc9, 0xcd, 0xfe, 0xfd, 0x0a, 0x9c, 0xc8, 0x5c, 0x10, 0x9b, 0xaa, 0x96, 0x5a, 0xda, 0xb7, + 0x5a, 0xea, 0x87, 0x00, 0x9a, 0x24, 0xf4, 0x82, 0x1d, 0x66, 0x8e, 0x0d, 0x1c, 0xd8, 0x1c, 0x53, + 0x16, 0xfc, 0xac, 0xa2, 0x82, 0x0d, 0x8a, 0xa2, 0x50, 0x19, 0x2f, 0xbe, 0x9a, 0x29, 0x54, 0x66, + 0xdc, 0x62, 0x30, 0x78, 0x7f, 0x6f, 0x31, 0x70, 0xe1, 0x04, 0xef, 0xa2, 0xca, 0xbe, 0x3d, 0x44, + 0x92, 0x2d, 0xcb, 0x5f, 0x98, 0x4d, 0x93, 0xc1, 0x59, 0xba, 0x0f, 0xf2, 0xfe, 0x67, 0xf4, 0x6e, + 0xa8, 0xc9, 0xef, 0x1c, 0x8f, 0xd7, 0x74, 0x05, 0x03, 0x39, 0x0d, 0xd8, 0xbd, 0xcc, 0xe2, 0x67, + 0x57, 0x21, 0x01, 0x78, 0x50, 0x85, 0x04, 0xec, 0xcf, 0x97, 0xa8, 0x1d, 0xcf, 0xfb, 0xa5, 0x6a, + 0xe2, 0x3c, 0x05, 0x83, 0x4e, 0x27, 0xd9, 0x08, 0xba, 0x6e, 0xf3, 0x9b, 0x66, 0xad, 0x58, 0x40, + 0xd1, 0x02, 0x0c, 0x34, 0x75, 0x9d, 0x93, 0x83, 0x7c, 0x4f, 0xed, 0x12, 0x75, 0x12, 0x82, 0x19, + 0x15, 0xf4, 0x18, 0x0c, 0x24, 0x4e, 0x4b, 0xa6, 0x5c, 0xb1, 0x34, 0xdb, 0x55, 0xa7, 0x15, 0x63, + 0xd6, 0x6a, 0xaa, 0xef, 0x81, 0x7d, 0xd4, 0xf7, 0x4b, 0x30, 0x1a, 0xbb, 0x2d, 0xdf, 0x49, 0x3a, + 0x11, 0x31, 0x8e, 0xf9, 0x74, 0xe4, 0x86, 0x09, 0xc4, 0x69, 0x5c, 0xfb, 0x37, 0x47, 0xe0, 0xcc, + 0xca, 0xcc, 0xa2, 0xac, 0xde, 0x7d, 0x6c, 0x59, 0x53, 0x79, 0x3c, 0xee, 0x5f, 0xd6, 0x54, 0x0f, + 0xee, 0x9e, 0x91, 0x35, 0xe5, 0x19, 0x59, 0x53, 0xe9, 0x14, 0x96, 0x72, 0x11, 0x29, 0x2c, 0x79, + 0x3d, 0xe8, 0x27, 0x85, 0xe5, 0xd8, 0xd2, 0xa8, 0xf6, 0xec, 0xd0, 0x81, 0xd2, 0xa8, 0x54, 0x8e, + 0x59, 0x21, 0xc9, 0x05, 0x3d, 0x3e, 0x55, 0x6e, 0x8e, 0x99, 0xca, 0xef, 0xe1, 0x89, 0x33, 0x42, + 0xd4, 0xbf, 0x5a, 0x7c, 0x07, 0xfa, 0xc8, 0xef, 0x11, 0xb9, 0x3b, 0x66, 0x4e, 0xd9, 0x50, 0x11, + 0x39, 0x65, 0x79, 0xdd, 0xd9, 0x37, 0xa7, 0xec, 0x25, 0x18, 0x6d, 0x78, 0x81, 0x4f, 0x96, 0xa3, + 0x20, 0x09, 0x1a, 0x81, 0x27, 0xcc, 0x7a, 0x25, 0x12, 0x66, 0x4c, 0x20, 0x4e, 0xe3, 0xf6, 0x4a, + 0x48, 0xab, 0x1d, 0x35, 0x21, 0x0d, 0x1e, 0x50, 0x42, 0xda, 0xcf, 0xea, 0xd4, 0xe9, 0x61, 0xf6, + 0x45, 0x3e, 0x54, 0xfc, 0x17, 0xe9, 0x27, 0x7f, 0x1a, 0xbd, 0xc5, 0xaf, 0xd3, 0xa3, 0x86, 0xf1, + 0x4c, 0xd0, 0xa6, 0x86, 0xdf, 0x08, 0x1b, 0x92, 0xd7, 0x8e, 0x61, 0xc2, 0xde, 0x5a, 0xd1, 0x6c, + 0xd4, 0x15, 0x7b, 0xba, 0x09, 0xa7, 0x3b, 0x72, 0x94, 0xd4, 0xee, 0x2f, 0x97, 0xe0, 0xfb, 0xf6, + 0xed, 0x02, 0xba, 0x03, 0x90, 0x38, 0x2d, 0x31, 0x51, 0xc5, 0x81, 0xc9, 0x11, 0xc3, 0x2b, 0x57, + 0x25, 0x3d, 0x5e, 0x93, 0x44, 0xfd, 0x65, 0x47, 0x11, 0xf2, 0x37, 0x8b, 0xaa, 0x0c, 0xbc, 0xae, + 0xd2, 0x8d, 0x38, 0xf0, 0x08, 0x66, 0x10, 0xaa, 0xfe, 0x23, 0xd2, 0xd2, 0xf7, 0x3f, 0xab, 0xcf, + 0x87, 0x59, 0x2b, 0x16, 0x50, 0xf4, 0x02, 0x0c, 0x3b, 0x9e, 0xc7, 0xf3, 0x63, 0x48, 0x2c, 0xee, + 0xd3, 0xd1, 0x35, 0xe4, 0x34, 0x08, 0x9b, 0x78, 0xf6, 0x9f, 0x96, 0x60, 0x62, 0x1f, 0x99, 0xd2, + 0x95, 0xf1, 0x57, 0xe9, 0x3b, 0xe3, 0x4f, 0xe4, 0x28, 0x0c, 0xf6, 0xc8, 0x51, 0x78, 0x01, 0x86, + 0x13, 0xe2, 0xb4, 0x45, 0x40, 0x96, 0xf0, 0x04, 0xe8, 0x13, 0x60, 0x0d, 0xc2, 0x26, 0x1e, 0x95, + 0x62, 0x63, 0x4e, 0xa3, 0x41, 0xe2, 0x58, 0x26, 0x21, 0x08, 0x6f, 0x6a, 0x61, 0x19, 0x0e, 0xcc, + 0x49, 0x3d, 0x9d, 0x62, 0x81, 0x33, 0x2c, 0xb3, 0x03, 0x5e, 0xeb, 0x73, 0xc0, 0xbf, 0x56, 0x82, + 0xc7, 0xf7, 0xd4, 0x6e, 0x7d, 0xe7, 0x87, 0x74, 0x62, 0x12, 0x65, 0x27, 0xce, 0x8d, 0x98, 0x44, + 0x98, 0x41, 0xf8, 0x28, 0x85, 0xa1, 0x71, 0xbf, 0x76, 0xd1, 0xc9, 0x4b, 0x7c, 0x94, 0x52, 0x2c, + 0x70, 0x86, 0xe5, 0x61, 0xa7, 0xe5, 0xdf, 0x2f, 0xc1, 0x93, 0x7d, 0xd8, 0x00, 0x05, 0x26, 0x79, + 0xa5, 0x53, 0xed, 0xca, 0x0f, 0x28, 0x23, 0xf2, 0x90, 0xc3, 0xf5, 0xf5, 0x12, 0x9c, 0xef, 0xad, + 0x8a, 0xd1, 0x8f, 0xc1, 0x89, 0x48, 0x45, 0x61, 0x99, 0x59, 0x7a, 0xa7, 0xb9, 0x27, 0x21, 0x05, + 0xc2, 0x59, 0x5c, 0x34, 0x09, 0x10, 0x3a, 0xc9, 0x46, 0x7c, 0x69, 0xdb, 0x8d, 0x13, 0x51, 0x85, + 0x66, 0x8c, 0x9f, 0x5d, 0xc9, 0x56, 0x6c, 0x60, 0x50, 0x76, 0xec, 0xdf, 0x6c, 0x70, 0x3d, 0x48, + 0xf8, 0x43, 0x7c, 0x1b, 0x71, 0x5a, 0xde, 0xd9, 0x61, 0x80, 0x70, 0x16, 0x97, 0xb2, 0x63, 0xa7, + 0xa3, 0xbc, 0xa3, 0x7c, 0x7f, 0xc1, 0xd8, 0x2d, 0xa8, 0x56, 0x6c, 0x60, 0x64, 0xf3, 0x0f, 0x2b, + 0xfb, 0xe7, 0x1f, 0xda, 0xff, 0xa4, 0x04, 0xe7, 0x7a, 0x9a, 0x72, 0xfd, 0x2d, 0xc0, 0x87, 0x2f, + 0x67, 0xf0, 0x70, 0x73, 0xe7, 0x80, 0xb9, 0x6d, 0x7f, 0xdc, 0x63, 0xa6, 0x89, 0xdc, 0xb6, 0xc3, + 0x27, 0x87, 0x3f, 0x7c, 0xe3, 0xd9, 0x95, 0xce, 0x36, 0x70, 0x80, 0x74, 0xb6, 0xcc, 0xc7, 0xa8, + 0xf4, 0xb9, 0x90, 0xff, 0xbc, 0xdc, 0x73, 0x78, 0xe9, 0xd6, 0xaf, 0x2f, 0x3f, 0xed, 0x2c, 0x9c, + 0x74, 0x7d, 0x76, 0x7f, 0xd3, 0x4a, 0x67, 0x4d, 0x14, 0x26, 0x29, 0xa5, 0x6f, 0x4f, 0x9f, 0xcf, + 0xc0, 0x71, 0xd7, 0x13, 0x0f, 0x61, 0x7a, 0xe1, 0xe1, 0x86, 0xf4, 0x60, 0x09, 0xae, 0x68, 0x09, + 0xce, 0xca, 0xa1, 0xd8, 0x70, 0x22, 0xd2, 0x14, 0x6a, 0x24, 0x16, 0x09, 0x15, 0xe7, 0x78, 0x52, + 0x46, 0x0e, 0x02, 0xce, 0x7f, 0x8e, 0x5d, 0x99, 0x13, 0x84, 0x6e, 0x43, 0x6c, 0x72, 0xf4, 0x95, + 0x39, 0xb4, 0x11, 0x73, 0x98, 0xfd, 0x21, 0xa8, 0xa9, 0xf7, 0xe7, 0x61, 0xdd, 0x6a, 0xd2, 0x75, + 0x85, 0x75, 0xab, 0x19, 0x67, 0x60, 0xd1, 0xaf, 0x45, 0x4d, 0xe2, 0xcc, 0xea, 0xb9, 0x46, 0x76, + 0x98, 0x7d, 0x6c, 0xff, 0x10, 0x8c, 0x28, 0x3f, 0x4b, 0xbf, 0x17, 0x09, 0xd9, 0x5f, 0x1c, 0x84, + 0xd1, 0x54, 0x71, 0xc0, 0x94, 0x83, 0xd5, 0xda, 0xd7, 0xc1, 0xca, 0xc2, 0xf4, 0x3b, 0xbe, 0xbc, + 0x65, 0xcc, 0x08, 0xd3, 0xef, 0xf8, 0x04, 0x73, 0x18, 0x35, 0x6f, 0x9b, 0xd1, 0x0e, 0xee, 0xf8, + 0x22, 0x9c, 0x56, 0x99, 0xb7, 0xb3, 0xac, 0x15, 0x0b, 0x28, 0xfa, 0xb8, 0x05, 0x23, 0x31, 0xf3, + 0xde, 0x73, 0xf7, 0xb4, 0x98, 0x74, 0x57, 0x8f, 0x5e, 0xfb, 0x50, 0x15, 0xc2, 0x64, 0x11, 0x32, + 0x66, 0x0b, 0x4e, 0x71, 0x44, 0x9f, 0xb2, 0xa0, 0xa6, 0x2e, 0x43, 0x11, 0x57, 0x01, 0xae, 0x14, + 0x5b, 0x7b, 0x91, 0xfb, 0x35, 0xd5, 0x41, 0x88, 0x2a, 0x82, 0x87, 0x35, 0x63, 0x14, 0x2b, 0xdf, + 0xf1, 0xd0, 0xf1, 0xf8, 0x8e, 0x21, 0xc7, 0x6f, 0xfc, 0x6e, 0xa8, 0xb5, 0x1d, 0xdf, 0x5d, 0x27, + 0x71, 0xc2, 0xdd, 0xb9, 0xb2, 0x24, 0xac, 0x6c, 0xc4, 0x1a, 0x4e, 0x15, 0x72, 0xcc, 0x5e, 0x2c, + 0x31, 0xfc, 0xaf, 0x4c, 0x21, 0xaf, 0xe8, 0x66, 0x6c, 0xe2, 0x98, 0xce, 0x62, 0x78, 0xa0, 0xce, + 0xe2, 0xe1, 0xbd, 0x9d, 0xc5, 0xf6, 0x3f, 0xb4, 0xe0, 0x6c, 0xee, 0x57, 0x7b, 0x78, 0x03, 0x1f, + 0xed, 0x2f, 0x55, 0xe0, 0x74, 0x4e, 0x95, 0x4f, 0xb4, 0x63, 0xce, 0x67, 0xab, 0x88, 0x18, 0x82, + 0xf4, 0x91, 0xb8, 0x1c, 0xc6, 0x9c, 0x49, 0x7c, 0xb0, 0xa3, 0x1a, 0x7d, 0x5c, 0x52, 0xbe, 0xbf, + 0xc7, 0x25, 0xc6, 0xb4, 0x1c, 0x78, 0xa0, 0xd3, 0xb2, 0xb2, 0xcf, 0x19, 0xc6, 0xaf, 0x59, 0x30, + 0xde, 0xee, 0x51, 0x5a, 0x5e, 0x38, 0x1e, 0x6f, 0x1e, 0x4f, 0xe1, 0xfa, 0xfa, 0x63, 0x77, 0x77, + 0x27, 0x7a, 0x56, 0xf4, 0xc7, 0x3d, 0x7b, 0x65, 0x7f, 0xbb, 0x0c, 0xac, 0xc4, 0x2c, 0xab, 0xe4, + 0xb6, 0x83, 0x3e, 0x66, 0x16, 0x0b, 0xb6, 0x8a, 0x2a, 0x6c, 0xcb, 0x89, 0xab, 0x62, 0xc3, 0x7c, + 0x04, 0xf3, 0x6a, 0x0f, 0x67, 0x85, 0x56, 0xa9, 0x0f, 0xa1, 0xe5, 0xc9, 0xaa, 0xcc, 0xe5, 0xe2, + 0xab, 0x32, 0xd7, 0xb2, 0x15, 0x99, 0xf7, 0xfe, 0xc4, 0x03, 0x0f, 0xe5, 0x27, 0xfe, 0x45, 0x8b, + 0x0b, 0x9e, 0xcc, 0x57, 0xd0, 0x96, 0x81, 0xb5, 0x87, 0x65, 0xf0, 0x0c, 0x54, 0x63, 0xe2, 0xad, + 0x5f, 0x21, 0x8e, 0x27, 0x2c, 0x08, 0x7d, 0x7e, 0x2d, 0xda, 0xb1, 0xc2, 0x60, 0xd7, 0xb6, 0x7a, + 0x5e, 0x70, 0xe7, 0x52, 0x3b, 0x4c, 0x76, 0x84, 0x2d, 0xa1, 0xaf, 0x6d, 0x55, 0x10, 0x6c, 0x60, + 0xd9, 0x7f, 0xab, 0xc4, 0x67, 0xa0, 0x08, 0x82, 0x78, 0x31, 0x73, 0xd1, 0x5e, 0xff, 0xf1, 0x03, + 0x1f, 0x01, 0x68, 0xa8, 0x2b, 0xea, 0xc5, 0x99, 0xd0, 0x95, 0x23, 0xdf, 0x9f, 0x2d, 0xe8, 0xe9, + 0xd7, 0xd0, 0x6d, 0xd8, 0xe0, 0x97, 0x92, 0xa5, 0xe5, 0x7d, 0x65, 0x69, 0x4a, 0xac, 0x0c, 0xec, + 0xa3, 0xed, 0xfe, 0xd4, 0x82, 0x94, 0x45, 0x84, 0x42, 0xa8, 0xd0, 0xee, 0xee, 0x14, 0x73, 0xfb, + 0xbe, 0x49, 0x9a, 0x8a, 0x46, 0x31, 0xed, 0xd9, 0x4f, 0xcc, 0x19, 0x21, 0x4f, 0xc4, 0x4a, 0xf0, + 0x51, 0xbd, 0x5e, 0x1c, 0xc3, 0x2b, 0x41, 0xb0, 0xc9, 0x0f, 0x36, 0x75, 0xdc, 0x85, 0xfd, 0x22, + 0x9c, 0xea, 0xea, 0x14, 0xbb, 0x53, 0x2b, 0xa0, 0xda, 0x27, 0x33, 0x5d, 0x59, 0x02, 0x27, 0xe6, + 0x30, 0xfb, 0xeb, 0x16, 0x9c, 0xcc, 0x92, 0x47, 0x6f, 0x59, 0x70, 0x2a, 0xce, 0xd2, 0x3b, 0xae, + 0xb1, 0x53, 0xf1, 0x8e, 0x5d, 0x20, 0xdc, 0xdd, 0x09, 0xfb, 0xff, 0x8a, 0xc9, 0x7f, 0xcb, 0xf5, + 0x9b, 0xc1, 0x1d, 0x65, 0x98, 0x58, 0x3d, 0x0d, 0x13, 0xba, 0x1e, 0x1b, 0x1b, 0xa4, 0xd9, 0xf1, + 0xba, 0x32, 0x47, 0x57, 0x44, 0x3b, 0x56, 0x18, 0x2c, 0x51, 0xae, 0x23, 0xca, 0xb6, 0x67, 0x26, + 0xe5, 0xac, 0x68, 0xc7, 0x0a, 0x03, 0x3d, 0x0f, 0x23, 0xc6, 0x4b, 0xca, 0x79, 0xc9, 0x0c, 0x72, + 0x43, 0x65, 0xc6, 0x38, 0x85, 0x85, 0x26, 0x01, 0x94, 0x91, 0x23, 0x55, 0x24, 0x73, 0x14, 0x29, + 0x49, 0x14, 0x63, 0x03, 0x83, 0xa5, 0xa5, 0x7a, 0x9d, 0x98, 0xf9, 0xf8, 0x07, 0x75, 0x29, 0xd1, + 0x19, 0xd1, 0x86, 0x15, 0x94, 0x4a, 0x93, 0xb6, 0xe3, 0x77, 0x1c, 0x8f, 0x8e, 0x90, 0xd8, 0xfa, + 0xa9, 0x65, 0xb8, 0xa8, 0x20, 0xd8, 0xc0, 0xa2, 0x6f, 0x9c, 0xb8, 0x6d, 0xf2, 0x4a, 0xe0, 0xcb, + 0x38, 0x35, 0x7d, 0xec, 0x23, 0xda, 0xb1, 0xc2, 0xb0, 0xff, 0xab, 0x05, 0x27, 0x74, 0x92, 0x3b, + 0xbf, 0x3d, 0xdb, 0xdc, 0xa9, 0x5a, 0xfb, 0xee, 0x54, 0xd3, 0xd9, 0xbf, 0xa5, 0xbe, 0xb2, 0x7f, + 0xcd, 0xc4, 0xdc, 0xf2, 0x9e, 0x89, 0xb9, 0xdf, 0xaf, 0x6f, 0x66, 0xe5, 0x19, 0xbc, 0xc3, 0x79, + 0xb7, 0xb2, 0x22, 0x1b, 0x06, 0x1b, 0x8e, 0xaa, 0xf0, 0x32, 0xc2, 0xf7, 0x0e, 0x33, 0xd3, 0x0c, + 0x49, 0x40, 0xec, 0x25, 0xa8, 0xa9, 0xd3, 0x0f, 0xb9, 0x51, 0xb5, 0xf2, 0x37, 0xaa, 0x7d, 0x25, + 0x08, 0xd6, 0xd7, 0xbe, 0xf1, 0x9d, 0x27, 0xde, 0xf1, 0x7b, 0xdf, 0x79, 0xe2, 0x1d, 0x7f, 0xf4, + 0x9d, 0x27, 0xde, 0xf1, 0xf1, 0xbb, 0x4f, 0x58, 0xdf, 0xb8, 0xfb, 0x84, 0xf5, 0x7b, 0x77, 0x9f, + 0xb0, 0xfe, 0xe8, 0xee, 0x13, 0xd6, 0xb7, 0xef, 0x3e, 0x61, 0x7d, 0xe1, 0x3f, 0x3d, 0xf1, 0x8e, + 0x57, 0x72, 0x03, 0x15, 0xe9, 0x8f, 0x67, 0x1b, 0xcd, 0xa9, 0xad, 0x8b, 0x2c, 0x56, 0x8e, 0x2e, + 0xaf, 0x29, 0x63, 0x4e, 0x4d, 0xc9, 0xe5, 0xf5, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x87, 0xd4, + 0x96, 0xc0, 0xad, 0xe1, 0x00, 0x00, } func (m *AWSAuthConfig) Marshal() (dAtA []byte, err error) { @@ -4543,6 +5161,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))) @@ -5123,6 +5746,47 @@ func (m *ApplicationMatchExpression) MarshalToSizedBuffer(dAtA []byte) (int, err return len(dAtA) - i, nil } +func (m *ApplicationPreservedFields) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ApplicationPreservedFields) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ApplicationPreservedFields) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Labels) > 0 { + for iNdEx := len(m.Labels) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Labels[iNdEx]) + copy(dAtA[i:], m.Labels[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Labels[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Annotations) > 0 { + for iNdEx := len(m.Annotations) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Annotations[iNdEx]) + copy(dAtA[i:], m.Annotations[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Annotations[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *ApplicationSet) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -5196,11 +5860,16 @@ func (m *ApplicationSetApplicationStatus) MarshalToSizedBuffer(dAtA []byte) (int _ = i var l int _ = l + i -= len(m.Step) + copy(dAtA[i:], m.Step) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Step))) + i-- + dAtA[i] = 0x2a i -= len(m.Status) copy(dAtA[i:], m.Status) i = encodeVarintGenerated(dAtA, i, uint64(len(m.Status))) i-- - dAtA[i] = 0x2a + dAtA[i] = 0x22 i -= len(m.Message) copy(dAtA[i:], m.Message) i = encodeVarintGenerated(dAtA, i, uint64(len(m.Message))) @@ -5301,6 +5970,18 @@ func (m *ApplicationSetGenerator) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l + if m.Plugin != nil { + { + size, err := m.Plugin.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } if m.Selector != nil { { size, err := m.Selector.MarshalToSizedBuffer(dAtA[:i]) @@ -5479,6 +6160,18 @@ func (m *ApplicationSetNestedGenerator) MarshalToSizedBuffer(dAtA []byte) (int, _ = i var l int _ = l + if m.Plugin != nil { + { + size, err := m.Plugin.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } if m.Selector != nil { { size, err := m.Selector.MarshalToSizedBuffer(dAtA[:i]) @@ -5590,6 +6283,52 @@ func (m *ApplicationSetNestedGenerator) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *ApplicationSetResourceIgnoreDifferences) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ApplicationSetResourceIgnoreDifferences) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ApplicationSetResourceIgnoreDifferences) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.JQPathExpressions) > 0 { + for iNdEx := len(m.JQPathExpressions) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.JQPathExpressions[iNdEx]) + copy(dAtA[i:], m.JQPathExpressions[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.JQPathExpressions[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + if len(m.JSONPointers) > 0 { + for iNdEx := len(m.JSONPointers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.JSONPointers[iNdEx]) + copy(dAtA[i:], m.JSONPointers[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.JSONPointers[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *ApplicationSetRolloutStep) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -5696,6 +6435,56 @@ 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-- { + { + size, err := m.IgnoreApplicationDifferences[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + } + i-- + if m.ApplyNestedSelectors { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x40 + if len(m.GoTemplateOptions) > 0 { + for iNdEx := len(m.GoTemplateOptions) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.GoTemplateOptions[iNdEx]) + copy(dAtA[i:], m.GoTemplateOptions[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.GoTemplateOptions[iNdEx]))) + i-- + dAtA[i] = 0x3a + } + } + if m.PreservedFields != nil { + { + size, err := m.PreservedFields.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } if m.Strategy != nil { { size, err := m.Strategy.MarshalToSizedBuffer(dAtA[:i]) @@ -5866,6 +6655,13 @@ func (m *ApplicationSetSyncPolicy) MarshalToSizedBuffer(dAtA []byte) (int, error _ = i var l int _ = l + if m.ApplicationsSync != nil { + i -= len(*m.ApplicationsSync) + copy(dAtA[i:], *m.ApplicationsSync) + i = encodeVarintGenerated(dAtA, i, uint64(len(*m.ApplicationsSync))) + i-- + dAtA[i] = 0x12 + } i-- if m.PreserveResourcesOnDeletion { dAtA[i] = 1 @@ -6030,6 +6826,30 @@ func (m *ApplicationSetTerminalGenerator) MarshalToSizedBuffer(dAtA []byte) (int _ = i var l int _ = l + if m.Selector != nil { + { + size, err := m.Selector.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + if m.Plugin != nil { + { + size, err := m.Plugin.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + } if m.PullRequest != nil { { size, err := m.PullRequest.MarshalToSizedBuffer(dAtA[:i]) @@ -6272,6 +7092,18 @@ func (m *ApplicationSourceHelm) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ValuesObject != nil { + { + size, err := m.ValuesObject.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } i-- if m.SkipCrds { dAtA[i] = 1 @@ -6432,6 +7264,64 @@ func (m *ApplicationSourceKustomize) MarshalToSizedBuffer(dAtA []byte) (int, err var l int _ = l i-- + if m.LabelWithoutSelector { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x70 + 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-- { + { + size, err := m.Patches[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + } + } + if len(m.Replicas) > 0 { + for iNdEx := len(m.Replicas) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Replicas[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + } + } + i-- + if m.CommonAnnotationsEnvsubst { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x50 + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0x4a + i-- if m.ForceCommonAnnotations { dAtA[i] = 1 } else { @@ -6605,38 +7495,29 @@ func (m *ApplicationSourcePluginParameter) MarshalToSizedBuffer(dAtA []byte) (in i-- dAtA[i] = 0x2a } - if len(m.Array) > 0 { - for iNdEx := len(m.Array) - 1; iNdEx >= 0; iNdEx-- { - i -= len(m.Array[iNdEx]) - copy(dAtA[i:], m.Array[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(m.Array[iNdEx]))) - i-- - dAtA[i] = 0x22 + if m.OptionalArray != nil { + { + size, err := m.OptionalArray.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x22 } - if len(m.Map) > 0 { - keysForMap := make([]string, 0, len(m.Map)) - for k := range m.Map { - keysForMap = append(keysForMap, string(k)) - } - github_com_gogo_protobuf_sortkeys.Strings(keysForMap) - for iNdEx := len(keysForMap) - 1; iNdEx >= 0; iNdEx-- { - v := m.Map[string(keysForMap[iNdEx])] - baseI := i - i -= len(v) - copy(dAtA[i:], v) - i = encodeVarintGenerated(dAtA, i, uint64(len(v))) - i-- - dAtA[i] = 0x12 - i -= len(keysForMap[iNdEx]) - copy(dAtA[i:], keysForMap[iNdEx]) - i = encodeVarintGenerated(dAtA, i, uint64(len(keysForMap[iNdEx]))) - i-- - dAtA[i] = 0xa - i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) - i-- - dAtA[i] = 0x1a + if m.OptionalMap != nil { + { + size, err := m.OptionalMap.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x1a } i -= len(m.Name) copy(dAtA[i:], m.Name) @@ -6775,6 +7656,11 @@ func (m *ApplicationStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + i -= len(m.ControllerNamespace) + copy(dAtA[i:], m.ControllerNamespace) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.ControllerNamespace))) + i-- + dAtA[i] = 0x6a if len(m.SourceTypes) > 0 { for iNdEx := len(m.SourceTypes) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.SourceTypes[iNdEx]) @@ -7127,6 +8013,83 @@ func (m *BasicAuthBitbucketServer) MarshalToSizedBuffer(dAtA []byte) (int, error return len(dAtA) - i, nil } +func (m *BearerTokenBitbucketCloud) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *BearerTokenBitbucketCloud) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *BearerTokenBitbucketCloud) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.TokenRef != nil { + { + size, err := m.TokenRef.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ChartDetails) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ChartDetails) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ChartDetails) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Maintainers) > 0 { + for iNdEx := len(m.Maintainers) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Maintainers[iNdEx]) + copy(dAtA[i:], m.Maintainers[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Maintainers[iNdEx]))) + i-- + dAtA[i] = 0x1a + } + } + i -= len(m.Home) + copy(dAtA[i:], m.Home) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Home))) + i-- + dAtA[i] = 0x12 + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *Cluster) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -7630,6 +8593,20 @@ func (m *ComparedTo) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.IgnoreDifferences) > 0 { + for iNdEx := len(m.IgnoreDifferences) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.IgnoreDifferences[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } if len(m.Sources) > 0 { for iNdEx := len(m.Sources) - 1; iNdEx >= 0; iNdEx-- { { @@ -8078,6 +9055,30 @@ func (m *GitGenerator) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Values) > 0 { + keysForValues := make([]string, 0, len(m.Values)) + for k := range m.Values { + keysForValues = append(keysForValues, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForValues) + for iNdEx := len(keysForValues) - 1; iNdEx >= 0; iNdEx-- { + v := m.Values[string(keysForValues[iNdEx])] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintGenerated(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(keysForValues[iNdEx]) + copy(dAtA[i:], keysForValues[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(keysForValues[iNdEx]))) + i-- + dAtA[i] = 0xa + i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x42 + } + } i -= len(m.PathParamPrefix) copy(dAtA[i:], m.PathParamPrefix) i = encodeVarintGenerated(dAtA, i, uint64(len(m.PathParamPrefix))) @@ -8678,6 +9679,44 @@ func (m *KnownTypeField) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *KustomizeGvk) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *KustomizeGvk) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *KustomizeGvk) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Kind) + copy(dAtA[i:], m.Kind) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Kind))) + i-- + dAtA[i] = 0x1a + i -= len(m.Version) + copy(dAtA[i:], m.Version) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Version))) + i-- + dAtA[i] = 0x12 + i -= len(m.Group) + copy(dAtA[i:], m.Group) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Group))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *KustomizeOptions) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -8711,6 +9750,202 @@ func (m *KustomizeOptions) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *KustomizePatch) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *KustomizePatch) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *KustomizePatch) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Options) > 0 { + keysForOptions := make([]string, 0, len(m.Options)) + for k := range m.Options { + keysForOptions = append(keysForOptions, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForOptions) + for iNdEx := len(keysForOptions) - 1; iNdEx >= 0; iNdEx-- { + v := m.Options[string(keysForOptions[iNdEx])] + baseI := i + i-- + if v { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + i -= len(keysForOptions[iNdEx]) + copy(dAtA[i:], keysForOptions[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(keysForOptions[iNdEx]))) + i-- + dAtA[i] = 0xa + i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x22 + } + } + if m.Target != nil { + { + size, err := m.Target.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + i -= len(m.Patch) + copy(dAtA[i:], m.Patch) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Patch))) + i-- + dAtA[i] = 0x12 + i -= len(m.Path) + copy(dAtA[i:], m.Path) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Path))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *KustomizeReplica) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *KustomizeReplica) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *KustomizeReplica) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Count.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *KustomizeResId) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *KustomizeResId) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *KustomizeResId) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0x1a + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + { + size, err := m.KustomizeGvk.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *KustomizeSelector) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *KustomizeSelector) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *KustomizeSelector) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.LabelSelector) + copy(dAtA[i:], m.LabelSelector) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.LabelSelector))) + i-- + dAtA[i] = 0x1a + i -= len(m.AnnotationSelector) + copy(dAtA[i:], m.AnnotationSelector) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.AnnotationSelector))) + i-- + dAtA[i] = 0x12 + { + size, err := m.KustomizeResId.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *ListGenerator) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -8731,6 +9966,11 @@ func (m *ListGenerator) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + i -= len(m.ElementsYaml) + copy(dAtA[i:], m.ElementsYaml) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.ElementsYaml))) + i-- + dAtA[i] = 0x1a { size, err := m.Template.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -9200,6 +10440,85 @@ func (m *OperationState) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *OptionalArray) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *OptionalArray) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OptionalArray) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Array) > 0 { + for iNdEx := len(m.Array) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Array[iNdEx]) + copy(dAtA[i:], m.Array[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Array[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *OptionalMap) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *OptionalMap) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OptionalMap) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Map) > 0 { + keysForMap := make([]string, 0, len(m.Map)) + for k := range m.Map { + keysForMap = append(keysForMap, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForMap) + for iNdEx := len(keysForMap) - 1; iNdEx >= 0; iNdEx-- { + v := m.Map[string(keysForMap[iNdEx])] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintGenerated(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(keysForMap[iNdEx]) + copy(dAtA[i:], keysForMap[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(keysForMap[iNdEx]))) + i-- + dAtA[i] = 0xa + i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *OrphanedResourceKey) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -9335,6 +10654,168 @@ func (m *OverrideIgnoreDiff) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *PluginConfigMapRef) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PluginConfigMapRef) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PluginConfigMapRef) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *PluginGenerator) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PluginGenerator) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PluginGenerator) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Values) > 0 { + keysForValues := make([]string, 0, len(m.Values)) + for k := range m.Values { + keysForValues = append(keysForValues, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForValues) + for iNdEx := len(keysForValues) - 1; iNdEx >= 0; iNdEx-- { + v := m.Values[string(keysForValues[iNdEx])] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintGenerated(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(keysForValues[iNdEx]) + copy(dAtA[i:], keysForValues[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(keysForValues[iNdEx]))) + i-- + dAtA[i] = 0xa + i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x2a + } + } + { + size, err := m.Template.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if m.RequeueAfterSeconds != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.RequeueAfterSeconds)) + i-- + dAtA[i] = 0x18 + } + { + size, err := m.Input.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + { + size, err := m.ConfigMapRef.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *PluginInput) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PluginInput) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PluginInput) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Parameters) > 0 { + keysForParameters := make([]string, 0, len(m.Parameters)) + for k := range m.Parameters { + keysForParameters = append(keysForParameters, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForParameters) + for iNdEx := len(keysForParameters) - 1; iNdEx >= 0; iNdEx-- { + v := m.Parameters[string(keysForParameters[iNdEx])] + baseI := i + { + size, err := (&v).MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + i -= len(keysForParameters[iNdEx]) + copy(dAtA[i:], keysForParameters[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(keysForParameters[iNdEx]))) + i-- + dAtA[i] = 0xa + i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *ProjectRole) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -9420,6 +10901,30 @@ func (m *PullRequestGenerator) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.AzureDevOps != nil { + { + size, err := m.AzureDevOps.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + if m.Bitbucket != nil { + { + size, err := m.Bitbucket.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } { size, err := m.Template.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -9500,7 +11005,7 @@ func (m *PullRequestGenerator) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *PullRequestGeneratorBitbucketServer) Marshal() (dAtA []byte, err error) { +func (m *PullRequestGeneratorAzureDevOps) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -9510,12 +11015,138 @@ func (m *PullRequestGeneratorBitbucketServer) Marshal() (dAtA []byte, err error) return dAtA[:n], nil } -func (m *PullRequestGeneratorBitbucketServer) MarshalTo(dAtA []byte) (int, error) { +func (m *PullRequestGeneratorAzureDevOps) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *PullRequestGeneratorBitbucketServer) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *PullRequestGeneratorAzureDevOps) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Labels) > 0 { + for iNdEx := len(m.Labels) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Labels[iNdEx]) + copy(dAtA[i:], m.Labels[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Labels[iNdEx]))) + i-- + dAtA[i] = 0x32 + } + } + if m.TokenRef != nil { + { + size, err := m.TokenRef.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + i -= len(m.API) + copy(dAtA[i:], m.API) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.API))) + i-- + dAtA[i] = 0x22 + i -= len(m.Repo) + copy(dAtA[i:], m.Repo) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Repo))) + i-- + dAtA[i] = 0x1a + i -= len(m.Project) + copy(dAtA[i:], m.Project) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Project))) + i-- + dAtA[i] = 0x12 + i -= len(m.Organization) + copy(dAtA[i:], m.Organization) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Organization))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *PullRequestGeneratorBitbucket) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PullRequestGeneratorBitbucket) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PullRequestGeneratorBitbucket) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.BearerToken != nil { + { + size, err := m.BearerToken.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + if m.BasicAuth != nil { + { + size, err := m.BasicAuth.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + i -= len(m.API) + copy(dAtA[i:], m.API) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.API))) + i-- + dAtA[i] = 0x1a + i -= len(m.Repo) + copy(dAtA[i:], m.Repo) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Repo))) + i-- + dAtA[i] = 0x12 + i -= len(m.Owner) + copy(dAtA[i:], m.Owner) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Owner))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *PullRequestGeneratorBitbucketServer) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PullRequestGeneratorBitbucketServer) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PullRequestGeneratorBitbucketServer) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -9570,6 +11201,13 @@ func (m *PullRequestGeneratorFilter) MarshalToSizedBuffer(dAtA []byte) (int, err _ = i var l int _ = l + if m.TargetBranchMatch != nil { + i -= len(*m.TargetBranchMatch) + copy(dAtA[i:], *m.TargetBranchMatch) + i = encodeVarintGenerated(dAtA, i, uint64(len(*m.TargetBranchMatch))) + i-- + dAtA[i] = 0x12 + } if m.BranchMatch != nil { i -= len(*m.BranchMatch) copy(dAtA[i:], *m.BranchMatch) @@ -9600,6 +11238,14 @@ func (m *PullRequestGeneratorGitLab) MarshalToSizedBuffer(dAtA []byte) (int, err _ = i var l int _ = l + i-- + if m.Insecure { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x30 i -= len(m.PullRequestState) copy(dAtA[i:], m.PullRequestState) i = encodeVarintGenerated(dAtA, i, uint64(len(m.PullRequestState))) @@ -9824,6 +11470,16 @@ func (m *RepoCreds) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + i-- + if m.ForceHttpBasicAuth { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa0 i -= len(m.Proxy) copy(dAtA[i:], m.Proxy) i = encodeVarintGenerated(dAtA, i, uint64(len(m.Proxy))) @@ -9965,6 +11621,16 @@ func (m *Repository) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + i-- + if m.ForceHttpBasicAuth { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xb0 i -= len(m.GCPServiceAccountKey) copy(dAtA[i:], m.GCPServiceAccountKey) i = encodeVarintGenerated(dAtA, i, uint64(len(m.GCPServiceAccountKey))) @@ -10265,6 +11931,16 @@ func (m *ResourceAction) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + i -= len(m.DisplayName) + copy(dAtA[i:], m.DisplayName) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.DisplayName))) + i-- + dAtA[i] = 0x2a + i -= len(m.IconClass) + copy(dAtA[i:], m.IconClass) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.IconClass))) + i-- + dAtA[i] = 0x22 i-- if m.Disabled { dAtA[i] = 1 @@ -10811,6 +12487,16 @@ func (m *ResourceOverride) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.IgnoreResourceUpdates.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 i-- if m.UseOpenLibs { dAtA[i] = 1 @@ -11124,6 +12810,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]) @@ -11267,6 +12963,42 @@ func (m *SCMProviderGenerator) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.AWSCodeCommit != nil { + { + size, err := m.AWSCodeCommit.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + } + if len(m.Values) > 0 { + keysForValues := make([]string, 0, len(m.Values)) + for k := range m.Values { + keysForValues = append(keysForValues, string(k)) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForValues) + for iNdEx := len(keysForValues) - 1; iNdEx >= 0; iNdEx-- { + v := m.Values[string(keysForValues[iNdEx])] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintGenerated(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(keysForValues[iNdEx]) + copy(dAtA[i:], keysForValues[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(keysForValues[iNdEx]))) + i-- + dAtA[i] = 0xa + i = encodeVarintGenerated(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x5a + } + } { size, err := m.Template.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -11376,6 +13108,61 @@ func (m *SCMProviderGenerator) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *SCMProviderGeneratorAWSCodeCommit) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SCMProviderGeneratorAWSCodeCommit) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SCMProviderGeneratorAWSCodeCommit) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i-- + if m.AllBranches { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + i -= len(m.Region) + copy(dAtA[i:], m.Region) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Region))) + i-- + dAtA[i] = 0x1a + i -= len(m.Role) + copy(dAtA[i:], m.Role) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Role))) + i-- + dAtA[i] = 0x12 + if len(m.TagFilters) > 0 { + for iNdEx := len(m.TagFilters) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TagFilters[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func (m *SCMProviderGeneratorAzureDevOps) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -11741,6 +13528,29 @@ func (m *SCMProviderGeneratorGitlab) MarshalToSizedBuffer(dAtA []byte) (int, err _ = i var l int _ = l + i -= len(m.Topic) + copy(dAtA[i:], m.Topic) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Topic))) + i-- + dAtA[i] = 0x42 + if m.IncludeSharedProjects != nil { + i-- + if *m.IncludeSharedProjects { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x38 + } + i-- + if m.Insecure { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x30 i-- if m.AllBranches { dAtA[i] = 1 @@ -12029,6 +13839,18 @@ func (m *SyncOperationResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ManagedNamespaceMetadata != nil { + { + size, err := m.ManagedNamespaceMetadata.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } if len(m.Revisions) > 0 { for iNdEx := len(m.Revisions) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.Revisions[iNdEx]) @@ -12497,6 +14319,39 @@ func (m *TLSClientConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *TagFilter) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TagFilter) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TagFilter) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i -= len(m.Value) + copy(dAtA[i:], m.Value) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Value))) + i-- + dAtA[i] = 0x12 + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintGenerated(dAtA []byte, offset int, v uint64) int { offset -= sovGenerated(v) base := offset @@ -12518,6 +14373,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 } @@ -12734,6 +14591,27 @@ func (m *ApplicationMatchExpression) Size() (n int) { return n } +func (m *ApplicationPreservedFields) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Annotations) > 0 { + for _, s := range m.Annotations { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } + if len(m.Labels) > 0 { + for _, s := range m.Labels { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + func (m *ApplicationSet) Size() (n int) { if m == nil { return 0 @@ -12765,6 +14643,8 @@ func (m *ApplicationSetApplicationStatus) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) l = len(m.Status) n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Step) + n += 1 + l + sovGenerated(uint64(l)) return n } @@ -12831,6 +14711,10 @@ func (m *ApplicationSetGenerator) Size() (n int) { l = m.Selector.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.Plugin != nil { + l = m.Plugin.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -12893,6 +14777,33 @@ func (m *ApplicationSetNestedGenerator) Size() (n int) { l = m.Selector.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.Plugin != nil { + l = m.Plugin.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + return n +} + +func (m *ApplicationSetResourceIgnoreDifferences) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + if len(m.JSONPointers) > 0 { + for _, s := range m.JSONPointers { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } + if len(m.JQPathExpressions) > 0 { + for _, s := range m.JQPathExpressions { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -12953,6 +14864,27 @@ func (m *ApplicationSetSpec) Size() (n int) { l = m.Strategy.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.PreservedFields != nil { + l = m.PreservedFields.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if len(m.GoTemplateOptions) > 0 { + for _, s := range m.GoTemplateOptions { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } + n += 2 + if len(m.IgnoreApplicationDifferences) > 0 { + for _, e := range m.IgnoreApplicationDifferences { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + if m.TemplatePatch != nil { + l = len(*m.TemplatePatch) + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -12999,6 +14931,10 @@ func (m *ApplicationSetSyncPolicy) Size() (n int) { var l int _ = l n += 2 + if m.ApplicationsSync != nil { + l = len(*m.ApplicationsSync) + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -13080,6 +15016,14 @@ func (m *ApplicationSetTerminalGenerator) Size() (n int) { l = m.PullRequest.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.Plugin != nil { + l = m.Plugin.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.Selector != nil { + l = m.Selector.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -13167,6 +15111,10 @@ func (m *ApplicationSourceHelm) Size() (n int) { n += 2 n += 2 n += 2 + if m.ValuesObject != nil { + l = m.ValuesObject.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -13233,6 +15181,28 @@ func (m *ApplicationSourceKustomize) Size() (n int) { } n += 2 n += 2 + l = len(m.Namespace) + n += 1 + l + sovGenerated(uint64(l)) + n += 2 + if len(m.Replicas) > 0 { + for _, e := range m.Replicas { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + if len(m.Patches) > 0 { + for _, e := range m.Patches { + l = e.Size() + 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)) + } + } + n += 2 return n } @@ -13267,19 +15237,13 @@ func (m *ApplicationSourcePluginParameter) Size() (n int) { _ = l l = len(m.Name) n += 1 + l + sovGenerated(uint64(l)) - if len(m.Map) > 0 { - for k, v := range m.Map { - _ = k - _ = v - mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v))) - n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize)) - } + if m.OptionalMap != nil { + l = m.OptionalMap.Size() + n += 1 + l + sovGenerated(uint64(l)) } - if len(m.Array) > 0 { - for _, s := range m.Array { - l = len(s) - n += 1 + l + sovGenerated(uint64(l)) - } + if m.OptionalArray != nil { + l = m.OptionalArray.Size() + n += 1 + l + sovGenerated(uint64(l)) } if m.String_ != nil { l = len(*m.String_) @@ -13382,6 +15346,8 @@ func (m *ApplicationStatus) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + l = len(m.ControllerNamespace) + n += 1 + l + sovGenerated(uint64(l)) return n } @@ -13477,6 +15443,38 @@ func (m *BasicAuthBitbucketServer) Size() (n int) { return n } +func (m *BearerTokenBitbucketCloud) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.TokenRef != nil { + l = m.TokenRef.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + return n +} + +func (m *ChartDetails) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Description) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Home) + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Maintainers) > 0 { + for _, s := range m.Maintainers { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + func (m *Cluster) Size() (n int) { if m == nil { return 0 @@ -13667,6 +15665,12 @@ func (m *ComparedTo) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if len(m.IgnoreDifferences) > 0 { + for _, e := range m.IgnoreDifferences { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -13842,6 +15846,14 @@ func (m *GitGenerator) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) l = len(m.PathParamPrefix) n += 1 + l + sovGenerated(uint64(l)) + if len(m.Values) > 0 { + for k, v := range m.Values { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v))) + n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize)) + } + } return n } @@ -14052,6 +16064,21 @@ func (m *KnownTypeField) Size() (n int) { return n } +func (m *KustomizeGvk) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Group) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Version) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Kind) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *KustomizeOptions) Size() (n int) { if m == nil { return 0 @@ -14065,6 +16092,74 @@ func (m *KustomizeOptions) Size() (n int) { return n } +func (m *KustomizePatch) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Path) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Patch) + n += 1 + l + sovGenerated(uint64(l)) + if m.Target != nil { + l = m.Target.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if len(m.Options) > 0 { + for k, v := range m.Options { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + 1 + n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize)) + } + } + return n +} + +func (m *KustomizeReplica) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + l = m.Count.Size() + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *KustomizeResId) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.KustomizeGvk.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Namespace) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *KustomizeSelector) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.KustomizeResId.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.AnnotationSelector) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.LabelSelector) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func (m *ListGenerator) Size() (n int) { if m == nil { return 0 @@ -14079,6 +16174,8 @@ func (m *ListGenerator) Size() (n int) { } l = m.Template.Size() n += 1 + l + sovGenerated(uint64(l)) + l = len(m.ElementsYaml) + n += 1 + l + sovGenerated(uint64(l)) return n } @@ -14244,6 +16341,38 @@ func (m *OperationState) Size() (n int) { return n } +func (m *OptionalArray) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Array) > 0 { + for _, s := range m.Array { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + +func (m *OptionalMap) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Map) > 0 { + for k, v := range m.Map { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v))) + n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize)) + } + } + return n +} + func (m *OrphanedResourceKey) Size() (n int) { if m == nil { return 0 @@ -14304,6 +16433,61 @@ func (m *OverrideIgnoreDiff) Size() (n int) { return n } +func (m *PluginConfigMapRef) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + +func (m *PluginGenerator) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.ConfigMapRef.Size() + n += 1 + l + sovGenerated(uint64(l)) + l = m.Input.Size() + n += 1 + l + sovGenerated(uint64(l)) + if m.RequeueAfterSeconds != nil { + n += 1 + sovGenerated(uint64(*m.RequeueAfterSeconds)) + } + l = m.Template.Size() + n += 1 + l + sovGenerated(uint64(l)) + if len(m.Values) > 0 { + for k, v := range m.Values { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v))) + n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize)) + } + } + return n +} + +func (m *PluginInput) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Parameters) > 0 { + for k, v := range m.Parameters { + _ = k + _ = v + l = v.Size() + mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + l + sovGenerated(uint64(l)) + n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize)) + } + } + return n +} + func (m *ProjectRole) Size() (n int) { if m == nil { return 0 @@ -14368,6 +16552,64 @@ func (m *PullRequestGenerator) Size() (n int) { } l = m.Template.Size() n += 1 + l + sovGenerated(uint64(l)) + if m.Bitbucket != nil { + l = m.Bitbucket.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.AzureDevOps != nil { + l = m.AzureDevOps.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + return n +} + +func (m *PullRequestGeneratorAzureDevOps) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Organization) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Project) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Repo) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.API) + n += 1 + l + sovGenerated(uint64(l)) + if m.TokenRef != nil { + l = m.TokenRef.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if len(m.Labels) > 0 { + for _, s := range m.Labels { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } + return n +} + +func (m *PullRequestGeneratorBitbucket) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Owner) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Repo) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.API) + n += 1 + l + sovGenerated(uint64(l)) + if m.BasicAuth != nil { + l = m.BasicAuth.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + if m.BearerToken != nil { + l = m.BearerToken.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -14400,6 +16642,10 @@ func (m *PullRequestGeneratorFilter) Size() (n int) { l = len(*m.BranchMatch) n += 1 + l + sovGenerated(uint64(l)) } + if m.TargetBranchMatch != nil { + l = len(*m.TargetBranchMatch) + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -14425,6 +16671,7 @@ func (m *PullRequestGeneratorGitLab) Size() (n int) { } l = len(m.PullRequestState) n += 1 + l + sovGenerated(uint64(l)) + n += 2 return n } @@ -14521,6 +16768,7 @@ func (m *RepoCreds) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) l = len(m.Proxy) n += 2 + l + sovGenerated(uint64(l)) + n += 3 return n } @@ -14582,6 +16830,7 @@ func (m *Repository) Size() (n int) { n += 2 + l + sovGenerated(uint64(l)) l = len(m.GCPServiceAccountKey) n += 2 + l + sovGenerated(uint64(l)) + n += 3 return n } @@ -14655,6 +16904,10 @@ func (m *ResourceAction) Size() (n int) { } } n += 2 + l = len(m.IconClass) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.DisplayName) + n += 1 + l + sovGenerated(uint64(l)) return n } @@ -14876,6 +17129,8 @@ func (m *ResourceOverride) Size() (n int) { } } n += 2 + l = m.IgnoreResourceUpdates.Size() + n += 1 + l + sovGenerated(uint64(l)) return n } @@ -15000,6 +17255,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 } @@ -15069,6 +17326,38 @@ func (m *SCMProviderGenerator) Size() (n int) { } l = m.Template.Size() n += 1 + l + sovGenerated(uint64(l)) + if len(m.Values) > 0 { + for k, v := range m.Values { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovGenerated(uint64(len(k))) + 1 + len(v) + sovGenerated(uint64(len(v))) + n += mapEntrySize + 1 + sovGenerated(uint64(mapEntrySize)) + } + } + if m.AWSCodeCommit != nil { + l = m.AWSCodeCommit.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + return n +} + +func (m *SCMProviderGeneratorAWSCodeCommit) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.TagFilters) > 0 { + for _, e := range m.TagFilters { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + l = len(m.Role) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Region) + n += 1 + l + sovGenerated(uint64(l)) + n += 2 return n } @@ -15216,6 +17505,12 @@ func (m *SCMProviderGeneratorGitlab) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } n += 2 + n += 2 + if m.IncludeSharedProjects != nil { + n += 2 + } + l = len(m.Topic) + n += 1 + l + sovGenerated(uint64(l)) return n } @@ -15339,6 +17634,10 @@ func (m *SyncOperationResult) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if m.ManagedNamespaceMetadata != nil { + l = m.ManagedNamespaceMetadata.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -15500,6 +17799,19 @@ func (m *TLSClientConfig) Size() (n int) { return n } +func (m *TagFilter) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Value) + n += 1 + l + sovGenerated(uint64(l)) + return n +} + func sovGenerated(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -15513,6 +17825,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 @@ -15692,6 +18005,17 @@ func (this *ApplicationMatchExpression) String() string { }, "") return s } +func (this *ApplicationPreservedFields) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ApplicationPreservedFields{`, + `Annotations:` + fmt.Sprintf("%v", this.Annotations) + `,`, + `Labels:` + fmt.Sprintf("%v", this.Labels) + `,`, + `}`, + }, "") + return s +} func (this *ApplicationSet) String() string { if this == nil { return "nil" @@ -15713,6 +18037,7 @@ func (this *ApplicationSetApplicationStatus) String() string { `LastTransitionTime:` + strings.Replace(fmt.Sprintf("%v", this.LastTransitionTime), "Time", "v1.Time", 1) + `,`, `Message:` + fmt.Sprintf("%v", this.Message) + `,`, `Status:` + fmt.Sprintf("%v", this.Status) + `,`, + `Step:` + fmt.Sprintf("%v", this.Step) + `,`, `}`, }, "") return s @@ -15745,6 +18070,7 @@ func (this *ApplicationSetGenerator) String() string { `Matrix:` + strings.Replace(this.Matrix.String(), "MatrixGenerator", "MatrixGenerator", 1) + `,`, `Merge:` + strings.Replace(this.Merge.String(), "MergeGenerator", "MergeGenerator", 1) + `,`, `Selector:` + strings.Replace(fmt.Sprintf("%v", this.Selector), "LabelSelector", "v1.LabelSelector", 1) + `,`, + `Plugin:` + strings.Replace(this.Plugin.String(), "PluginGenerator", "PluginGenerator", 1) + `,`, `}`, }, "") return s @@ -15779,6 +18105,19 @@ func (this *ApplicationSetNestedGenerator) String() string { `Matrix:` + strings.Replace(fmt.Sprintf("%v", this.Matrix), "JSON", "v11.JSON", 1) + `,`, `Merge:` + strings.Replace(fmt.Sprintf("%v", this.Merge), "JSON", "v11.JSON", 1) + `,`, `Selector:` + strings.Replace(fmt.Sprintf("%v", this.Selector), "LabelSelector", "v1.LabelSelector", 1) + `,`, + `Plugin:` + strings.Replace(this.Plugin.String(), "PluginGenerator", "PluginGenerator", 1) + `,`, + `}`, + }, "") + return s +} +func (this *ApplicationSetResourceIgnoreDifferences) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ApplicationSetResourceIgnoreDifferences{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `JSONPointers:` + fmt.Sprintf("%v", this.JSONPointers) + `,`, + `JQPathExpressions:` + fmt.Sprintf("%v", this.JQPathExpressions) + `,`, `}`, }, "") return s @@ -15823,12 +18162,22 @@ func (this *ApplicationSetSpec) String() string { repeatedStringForGenerators += strings.Replace(strings.Replace(f.String(), "ApplicationSetGenerator", "ApplicationSetGenerator", 1), `&`, ``, 1) + "," } repeatedStringForGenerators += "}" + repeatedStringForIgnoreApplicationDifferences := "[]ApplicationSetResourceIgnoreDifferences{" + for _, f := range this.IgnoreApplicationDifferences { + repeatedStringForIgnoreApplicationDifferences += strings.Replace(strings.Replace(f.String(), "ApplicationSetResourceIgnoreDifferences", "ApplicationSetResourceIgnoreDifferences", 1), `&`, ``, 1) + "," + } + repeatedStringForIgnoreApplicationDifferences += "}" s := strings.Join([]string{`&ApplicationSetSpec{`, `GoTemplate:` + fmt.Sprintf("%v", this.GoTemplate) + `,`, `Generators:` + repeatedStringForGenerators + `,`, `Template:` + strings.Replace(strings.Replace(this.Template.String(), "ApplicationSetTemplate", "ApplicationSetTemplate", 1), `&`, ``, 1) + `,`, `SyncPolicy:` + strings.Replace(this.SyncPolicy.String(), "ApplicationSetSyncPolicy", "ApplicationSetSyncPolicy", 1) + `,`, `Strategy:` + strings.Replace(this.Strategy.String(), "ApplicationSetStrategy", "ApplicationSetStrategy", 1) + `,`, + `PreservedFields:` + strings.Replace(this.PreservedFields.String(), "ApplicationPreservedFields", "ApplicationPreservedFields", 1) + `,`, + `GoTemplateOptions:` + fmt.Sprintf("%v", this.GoTemplateOptions) + `,`, + `ApplyNestedSelectors:` + fmt.Sprintf("%v", this.ApplyNestedSelectors) + `,`, + `IgnoreApplicationDifferences:` + repeatedStringForIgnoreApplicationDifferences + `,`, + `TemplatePatch:` + valueToStringGenerated(this.TemplatePatch) + `,`, `}`, }, "") return s @@ -15871,6 +18220,7 @@ func (this *ApplicationSetSyncPolicy) String() string { } s := strings.Join([]string{`&ApplicationSetSyncPolicy{`, `PreserveResourcesOnDeletion:` + fmt.Sprintf("%v", this.PreserveResourcesOnDeletion) + `,`, + `ApplicationsSync:` + valueToStringGenerated(this.ApplicationsSync) + `,`, `}`, }, "") return s @@ -15931,6 +18281,8 @@ func (this *ApplicationSetTerminalGenerator) String() string { `SCMProvider:` + strings.Replace(this.SCMProvider.String(), "SCMProviderGenerator", "SCMProviderGenerator", 1) + `,`, `ClusterDecisionResource:` + strings.Replace(this.ClusterDecisionResource.String(), "DuckTypeGenerator", "DuckTypeGenerator", 1) + `,`, `PullRequest:` + strings.Replace(this.PullRequest.String(), "PullRequestGenerator", "PullRequestGenerator", 1) + `,`, + `Plugin:` + strings.Replace(this.Plugin.String(), "PluginGenerator", "PluginGenerator", 1) + `,`, + `Selector:` + strings.Replace(fmt.Sprintf("%v", this.Selector), "LabelSelector", "v1.LabelSelector", 1) + `,`, `}`, }, "") return s @@ -15990,6 +18342,7 @@ func (this *ApplicationSourceHelm) String() string { `PassCredentials:` + fmt.Sprintf("%v", this.PassCredentials) + `,`, `IgnoreMissingValueFiles:` + fmt.Sprintf("%v", this.IgnoreMissingValueFiles) + `,`, `SkipCrds:` + fmt.Sprintf("%v", this.SkipCrds) + `,`, + `ValuesObject:` + strings.Replace(fmt.Sprintf("%v", this.ValuesObject), "RawExtension", "runtime.RawExtension", 1) + `,`, `}`, }, "") return s @@ -16020,6 +18373,16 @@ func (this *ApplicationSourceKustomize) String() string { if this == nil { return "nil" } + repeatedStringForReplicas := "[]KustomizeReplica{" + for _, f := range this.Replicas { + repeatedStringForReplicas += strings.Replace(strings.Replace(f.String(), "KustomizeReplica", "KustomizeReplica", 1), `&`, ``, 1) + "," + } + repeatedStringForReplicas += "}" + repeatedStringForPatches := "[]KustomizePatch{" + for _, f := range this.Patches { + repeatedStringForPatches += strings.Replace(strings.Replace(f.String(), "KustomizePatch", "KustomizePatch", 1), `&`, ``, 1) + "," + } + repeatedStringForPatches += "}" keysForCommonLabels := make([]string, 0, len(this.CommonLabels)) for k := range this.CommonLabels { keysForCommonLabels = append(keysForCommonLabels, k) @@ -16049,6 +18412,12 @@ func (this *ApplicationSourceKustomize) String() string { `CommonAnnotations:` + mapStringForCommonAnnotations + `,`, `ForceCommonLabels:` + fmt.Sprintf("%v", this.ForceCommonLabels) + `,`, `ForceCommonAnnotations:` + fmt.Sprintf("%v", this.ForceCommonAnnotations) + `,`, + `Namespace:` + fmt.Sprintf("%v", this.Namespace) + `,`, + `CommonAnnotationsEnvsubst:` + fmt.Sprintf("%v", this.CommonAnnotationsEnvsubst) + `,`, + `Replicas:` + repeatedStringForReplicas + `,`, + `Patches:` + repeatedStringForPatches + `,`, + `Components:` + fmt.Sprintf("%v", this.Components) + `,`, + `LabelWithoutSelector:` + fmt.Sprintf("%v", this.LabelWithoutSelector) + `,`, `}`, }, "") return s @@ -16079,20 +18448,10 @@ func (this *ApplicationSourcePluginParameter) String() string { if this == nil { return "nil" } - keysForMap := make([]string, 0, len(this.Map)) - for k := range this.Map { - keysForMap = append(keysForMap, k) - } - github_com_gogo_protobuf_sortkeys.Strings(keysForMap) - mapStringForMap := "map[string]string{" - for _, k := range keysForMap { - mapStringForMap += fmt.Sprintf("%v: %v,", k, this.Map[k]) - } - mapStringForMap += "}" s := strings.Join([]string{`&ApplicationSourcePluginParameter{`, `Name:` + fmt.Sprintf("%v", this.Name) + `,`, - `Map:` + mapStringForMap + `,`, - `Array:` + fmt.Sprintf("%v", this.Array) + `,`, + `OptionalMap:` + strings.Replace(this.OptionalMap.String(), "OptionalMap", "OptionalMap", 1) + `,`, + `OptionalArray:` + strings.Replace(this.OptionalArray.String(), "OptionalArray", "OptionalArray", 1) + `,`, `String_:` + valueToStringGenerated(this.String_) + `,`, `}`, }, "") @@ -16162,6 +18521,7 @@ func (this *ApplicationStatus) String() string { `Summary:` + strings.Replace(strings.Replace(this.Summary.String(), "ApplicationSummary", "ApplicationSummary", 1), `&`, ``, 1) + `,`, `ResourceHealthSource:` + fmt.Sprintf("%v", this.ResourceHealthSource) + `,`, `SourceTypes:` + fmt.Sprintf("%v", this.SourceTypes) + `,`, + `ControllerNamespace:` + fmt.Sprintf("%v", this.ControllerNamespace) + `,`, `}`, }, "") return s @@ -16238,6 +18598,28 @@ func (this *BasicAuthBitbucketServer) String() string { }, "") return s } +func (this *BearerTokenBitbucketCloud) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&BearerTokenBitbucketCloud{`, + `TokenRef:` + strings.Replace(this.TokenRef.String(), "SecretRef", "SecretRef", 1) + `,`, + `}`, + }, "") + return s +} +func (this *ChartDetails) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&ChartDetails{`, + `Description:` + fmt.Sprintf("%v", this.Description) + `,`, + `Home:` + fmt.Sprintf("%v", this.Home) + `,`, + `Maintainers:` + fmt.Sprintf("%v", this.Maintainers) + `,`, + `}`, + }, "") + return s +} func (this *Cluster) String() string { if this == nil { return "nil" @@ -16379,10 +18761,16 @@ func (this *ComparedTo) String() string { repeatedStringForSources += strings.Replace(strings.Replace(f.String(), "ApplicationSource", "ApplicationSource", 1), `&`, ``, 1) + "," } repeatedStringForSources += "}" + repeatedStringForIgnoreDifferences := "[]ResourceIgnoreDifferences{" + for _, f := range this.IgnoreDifferences { + repeatedStringForIgnoreDifferences += strings.Replace(strings.Replace(f.String(), "ResourceIgnoreDifferences", "ResourceIgnoreDifferences", 1), `&`, ``, 1) + "," + } + repeatedStringForIgnoreDifferences += "}" s := strings.Join([]string{`&ComparedTo{`, `Source:` + strings.Replace(strings.Replace(this.Source.String(), "ApplicationSource", "ApplicationSource", 1), `&`, ``, 1) + `,`, `Destination:` + strings.Replace(strings.Replace(this.Destination.String(), "ApplicationDestination", "ApplicationDestination", 1), `&`, ``, 1) + `,`, `Sources:` + repeatedStringForSources + `,`, + `IgnoreDifferences:` + repeatedStringForIgnoreDifferences + `,`, `}`, }, "") return s @@ -16519,6 +18907,16 @@ func (this *GitGenerator) String() string { repeatedStringForFiles += strings.Replace(strings.Replace(f.String(), "GitFileGeneratorItem", "GitFileGeneratorItem", 1), `&`, ``, 1) + "," } repeatedStringForFiles += "}" + keysForValues := make([]string, 0, len(this.Values)) + for k := range this.Values { + keysForValues = append(keysForValues, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForValues) + mapStringForValues := "map[string]string{" + for _, k := range keysForValues { + mapStringForValues += fmt.Sprintf("%v: %v,", k, this.Values[k]) + } + mapStringForValues += "}" s := strings.Join([]string{`&GitGenerator{`, `RepoURL:` + fmt.Sprintf("%v", this.RepoURL) + `,`, `Directories:` + repeatedStringForDirectories + `,`, @@ -16527,6 +18925,7 @@ func (this *GitGenerator) String() string { `RequeueAfterSeconds:` + valueToStringGenerated(this.RequeueAfterSeconds) + `,`, `Template:` + strings.Replace(strings.Replace(this.Template.String(), "ApplicationSetTemplate", "ApplicationSetTemplate", 1), `&`, ``, 1) + `,`, `PathParamPrefix:` + fmt.Sprintf("%v", this.PathParamPrefix) + `,`, + `Values:` + mapStringForValues + `,`, `}`, }, "") return s @@ -16708,6 +19107,18 @@ func (this *KnownTypeField) String() string { }, "") return s } +func (this *KustomizeGvk) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&KustomizeGvk{`, + `Group:` + fmt.Sprintf("%v", this.Group) + `,`, + `Version:` + fmt.Sprintf("%v", this.Version) + `,`, + `Kind:` + fmt.Sprintf("%v", this.Kind) + `,`, + `}`, + }, "") + return s +} func (this *KustomizeOptions) String() string { if this == nil { return "nil" @@ -16719,6 +19130,64 @@ func (this *KustomizeOptions) String() string { }, "") return s } +func (this *KustomizePatch) String() string { + if this == nil { + return "nil" + } + keysForOptions := make([]string, 0, len(this.Options)) + for k := range this.Options { + keysForOptions = append(keysForOptions, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForOptions) + mapStringForOptions := "map[string]bool{" + for _, k := range keysForOptions { + mapStringForOptions += fmt.Sprintf("%v: %v,", k, this.Options[k]) + } + mapStringForOptions += "}" + s := strings.Join([]string{`&KustomizePatch{`, + `Path:` + fmt.Sprintf("%v", this.Path) + `,`, + `Patch:` + fmt.Sprintf("%v", this.Patch) + `,`, + `Target:` + strings.Replace(this.Target.String(), "KustomizeSelector", "KustomizeSelector", 1) + `,`, + `Options:` + mapStringForOptions + `,`, + `}`, + }, "") + return s +} +func (this *KustomizeReplica) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&KustomizeReplica{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Count:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Count), "IntOrString", "intstr.IntOrString", 1), `&`, ``, 1) + `,`, + `}`, + }, "") + return s +} +func (this *KustomizeResId) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&KustomizeResId{`, + `KustomizeGvk:` + strings.Replace(strings.Replace(this.KustomizeGvk.String(), "KustomizeGvk", "KustomizeGvk", 1), `&`, ``, 1) + `,`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `Namespace:` + fmt.Sprintf("%v", this.Namespace) + `,`, + `}`, + }, "") + return s +} +func (this *KustomizeSelector) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&KustomizeSelector{`, + `KustomizeResId:` + strings.Replace(strings.Replace(this.KustomizeResId.String(), "KustomizeResId", "KustomizeResId", 1), `&`, ``, 1) + `,`, + `AnnotationSelector:` + fmt.Sprintf("%v", this.AnnotationSelector) + `,`, + `LabelSelector:` + fmt.Sprintf("%v", this.LabelSelector) + `,`, + `}`, + }, "") + return s +} func (this *ListGenerator) String() string { if this == nil { return "nil" @@ -16731,6 +19200,7 @@ func (this *ListGenerator) String() string { s := strings.Join([]string{`&ListGenerator{`, `Elements:` + repeatedStringForElements + `,`, `Template:` + strings.Replace(strings.Replace(this.Template.String(), "ApplicationSetTemplate", "ApplicationSetTemplate", 1), `&`, ``, 1) + `,`, + `ElementsYaml:` + fmt.Sprintf("%v", this.ElementsYaml) + `,`, `}`, }, "") return s @@ -16875,6 +19345,36 @@ func (this *OperationState) String() string { }, "") return s } +func (this *OptionalArray) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&OptionalArray{`, + `Array:` + fmt.Sprintf("%v", this.Array) + `,`, + `}`, + }, "") + return s +} +func (this *OptionalMap) String() string { + if this == nil { + return "nil" + } + keysForMap := make([]string, 0, len(this.Map)) + for k := range this.Map { + keysForMap = append(keysForMap, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForMap) + mapStringForMap := "map[string]string{" + for _, k := range keysForMap { + mapStringForMap += fmt.Sprintf("%v: %v,", k, this.Map[k]) + } + mapStringForMap += "}" + s := strings.Join([]string{`&OptionalMap{`, + `Map:` + mapStringForMap + `,`, + `}`, + }, "") + return s +} func (this *OrphanedResourceKey) String() string { if this == nil { return "nil" @@ -16915,6 +19415,60 @@ func (this *OverrideIgnoreDiff) String() string { }, "") return s } +func (this *PluginConfigMapRef) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PluginConfigMapRef{`, + `Name:` + fmt.Sprintf("%v", this.Name) + `,`, + `}`, + }, "") + return s +} +func (this *PluginGenerator) String() string { + if this == nil { + return "nil" + } + keysForValues := make([]string, 0, len(this.Values)) + for k := range this.Values { + keysForValues = append(keysForValues, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForValues) + mapStringForValues := "map[string]string{" + for _, k := range keysForValues { + mapStringForValues += fmt.Sprintf("%v: %v,", k, this.Values[k]) + } + mapStringForValues += "}" + s := strings.Join([]string{`&PluginGenerator{`, + `ConfigMapRef:` + strings.Replace(strings.Replace(this.ConfigMapRef.String(), "PluginConfigMapRef", "PluginConfigMapRef", 1), `&`, ``, 1) + `,`, + `Input:` + strings.Replace(strings.Replace(this.Input.String(), "PluginInput", "PluginInput", 1), `&`, ``, 1) + `,`, + `RequeueAfterSeconds:` + valueToStringGenerated(this.RequeueAfterSeconds) + `,`, + `Template:` + strings.Replace(strings.Replace(this.Template.String(), "ApplicationSetTemplate", "ApplicationSetTemplate", 1), `&`, ``, 1) + `,`, + `Values:` + mapStringForValues + `,`, + `}`, + }, "") + return s +} +func (this *PluginInput) String() string { + if this == nil { + return "nil" + } + keysForParameters := make([]string, 0, len(this.Parameters)) + for k := range this.Parameters { + keysForParameters = append(keysForParameters, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForParameters) + mapStringForParameters := "PluginParameters{" + for _, k := range keysForParameters { + mapStringForParameters += fmt.Sprintf("%v: %v,", k, this.Parameters[k]) + } + mapStringForParameters += "}" + s := strings.Join([]string{`&PluginInput{`, + `Parameters:` + mapStringForParameters + `,`, + `}`, + }, "") + return s +} func (this *ProjectRole) String() string { if this == nil { return "nil" @@ -16951,6 +19505,37 @@ func (this *PullRequestGenerator) String() string { `Filters:` + repeatedStringForFilters + `,`, `RequeueAfterSeconds:` + valueToStringGenerated(this.RequeueAfterSeconds) + `,`, `Template:` + strings.Replace(strings.Replace(this.Template.String(), "ApplicationSetTemplate", "ApplicationSetTemplate", 1), `&`, ``, 1) + `,`, + `Bitbucket:` + strings.Replace(this.Bitbucket.String(), "PullRequestGeneratorBitbucket", "PullRequestGeneratorBitbucket", 1) + `,`, + `AzureDevOps:` + strings.Replace(this.AzureDevOps.String(), "PullRequestGeneratorAzureDevOps", "PullRequestGeneratorAzureDevOps", 1) + `,`, + `}`, + }, "") + return s +} +func (this *PullRequestGeneratorAzureDevOps) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PullRequestGeneratorAzureDevOps{`, + `Organization:` + fmt.Sprintf("%v", this.Organization) + `,`, + `Project:` + fmt.Sprintf("%v", this.Project) + `,`, + `Repo:` + fmt.Sprintf("%v", this.Repo) + `,`, + `API:` + fmt.Sprintf("%v", this.API) + `,`, + `TokenRef:` + strings.Replace(this.TokenRef.String(), "SecretRef", "SecretRef", 1) + `,`, + `Labels:` + fmt.Sprintf("%v", this.Labels) + `,`, + `}`, + }, "") + return s +} +func (this *PullRequestGeneratorBitbucket) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PullRequestGeneratorBitbucket{`, + `Owner:` + fmt.Sprintf("%v", this.Owner) + `,`, + `Repo:` + fmt.Sprintf("%v", this.Repo) + `,`, + `API:` + fmt.Sprintf("%v", this.API) + `,`, + `BasicAuth:` + strings.Replace(this.BasicAuth.String(), "BasicAuthBitbucketServer", "BasicAuthBitbucketServer", 1) + `,`, + `BearerToken:` + strings.Replace(this.BearerToken.String(), "BearerTokenBitbucketCloud", "BearerTokenBitbucketCloud", 1) + `,`, `}`, }, "") return s @@ -16974,6 +19559,7 @@ func (this *PullRequestGeneratorFilter) String() string { } s := strings.Join([]string{`&PullRequestGeneratorFilter{`, `BranchMatch:` + valueToStringGenerated(this.BranchMatch) + `,`, + `TargetBranchMatch:` + valueToStringGenerated(this.TargetBranchMatch) + `,`, `}`, }, "") return s @@ -16988,6 +19574,7 @@ func (this *PullRequestGeneratorGitLab) String() string { `TokenRef:` + strings.Replace(this.TokenRef.String(), "SecretRef", "SecretRef", 1) + `,`, `Labels:` + fmt.Sprintf("%v", this.Labels) + `,`, `PullRequestState:` + fmt.Sprintf("%v", this.PullRequestState) + `,`, + `Insecure:` + fmt.Sprintf("%v", this.Insecure) + `,`, `}`, }, "") return s @@ -17052,6 +19639,7 @@ func (this *RepoCreds) String() string { `Type:` + fmt.Sprintf("%v", this.Type) + `,`, `GCPServiceAccountKey:` + fmt.Sprintf("%v", this.GCPServiceAccountKey) + `,`, `Proxy:` + fmt.Sprintf("%v", this.Proxy) + `,`, + `ForceHttpBasicAuth:` + fmt.Sprintf("%v", this.ForceHttpBasicAuth) + `,`, `}`, }, "") return s @@ -17098,6 +19686,7 @@ func (this *Repository) String() string { `Proxy:` + fmt.Sprintf("%v", this.Proxy) + `,`, `Project:` + fmt.Sprintf("%v", this.Project) + `,`, `GCPServiceAccountKey:` + fmt.Sprintf("%v", this.GCPServiceAccountKey) + `,`, + `ForceHttpBasicAuth:` + fmt.Sprintf("%v", this.ForceHttpBasicAuth) + `,`, `}`, }, "") return s @@ -17161,6 +19750,8 @@ func (this *ResourceAction) String() string { `Name:` + fmt.Sprintf("%v", this.Name) + `,`, `Params:` + repeatedStringForParams + `,`, `Disabled:` + fmt.Sprintf("%v", this.Disabled) + `,`, + `IconClass:` + fmt.Sprintf("%v", this.IconClass) + `,`, + `DisplayName:` + fmt.Sprintf("%v", this.DisplayName) + `,`, `}`, }, "") return s @@ -17328,6 +19919,7 @@ func (this *ResourceOverride) String() string { `Actions:` + fmt.Sprintf("%v", this.Actions) + `,`, `KnownTypeFields:` + repeatedStringForKnownTypeFields + `,`, `UseOpenLibs:` + fmt.Sprintf("%v", this.UseOpenLibs) + `,`, + `IgnoreResourceUpdates:` + strings.Replace(strings.Replace(this.IgnoreResourceUpdates.String(), "OverrideIgnoreDiff", "OverrideIgnoreDiff", 1), `&`, ``, 1) + `,`, `}`, }, "") return s @@ -17413,6 +20005,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 @@ -17440,6 +20033,16 @@ func (this *SCMProviderGenerator) String() string { repeatedStringForFilters += strings.Replace(strings.Replace(f.String(), "SCMProviderGeneratorFilter", "SCMProviderGeneratorFilter", 1), `&`, ``, 1) + "," } repeatedStringForFilters += "}" + keysForValues := make([]string, 0, len(this.Values)) + for k := range this.Values { + keysForValues = append(keysForValues, k) + } + github_com_gogo_protobuf_sortkeys.Strings(keysForValues) + mapStringForValues := "map[string]string{" + for _, k := range keysForValues { + mapStringForValues += fmt.Sprintf("%v: %v,", k, this.Values[k]) + } + mapStringForValues += "}" s := strings.Join([]string{`&SCMProviderGenerator{`, `Github:` + strings.Replace(this.Github.String(), "SCMProviderGeneratorGithub", "SCMProviderGeneratorGithub", 1) + `,`, `Gitlab:` + strings.Replace(this.Gitlab.String(), "SCMProviderGeneratorGitlab", "SCMProviderGeneratorGitlab", 1) + `,`, @@ -17451,6 +20054,26 @@ func (this *SCMProviderGenerator) String() string { `CloneProtocol:` + fmt.Sprintf("%v", this.CloneProtocol) + `,`, `RequeueAfterSeconds:` + valueToStringGenerated(this.RequeueAfterSeconds) + `,`, `Template:` + strings.Replace(strings.Replace(this.Template.String(), "ApplicationSetTemplate", "ApplicationSetTemplate", 1), `&`, ``, 1) + `,`, + `Values:` + mapStringForValues + `,`, + `AWSCodeCommit:` + strings.Replace(this.AWSCodeCommit.String(), "SCMProviderGeneratorAWSCodeCommit", "SCMProviderGeneratorAWSCodeCommit", 1) + `,`, + `}`, + }, "") + return s +} +func (this *SCMProviderGeneratorAWSCodeCommit) String() string { + if this == nil { + return "nil" + } + repeatedStringForTagFilters := "[]*TagFilter{" + for _, f := range this.TagFilters { + repeatedStringForTagFilters += strings.Replace(f.String(), "TagFilter", "TagFilter", 1) + "," + } + repeatedStringForTagFilters += "}" + s := strings.Join([]string{`&SCMProviderGeneratorAWSCodeCommit{`, + `TagFilters:` + repeatedStringForTagFilters + `,`, + `Role:` + fmt.Sprintf("%v", this.Role) + `,`, + `Region:` + fmt.Sprintf("%v", this.Region) + `,`, + `AllBranches:` + fmt.Sprintf("%v", this.AllBranches) + `,`, `}`, }, "") return s @@ -17547,6 +20170,9 @@ func (this *SCMProviderGeneratorGitlab) String() string { `API:` + fmt.Sprintf("%v", this.API) + `,`, `TokenRef:` + strings.Replace(this.TokenRef.String(), "SecretRef", "SecretRef", 1) + `,`, `AllBranches:` + fmt.Sprintf("%v", this.AllBranches) + `,`, + `Insecure:` + fmt.Sprintf("%v", this.Insecure) + `,`, + `IncludeSharedProjects:` + valueToStringGenerated(this.IncludeSharedProjects) + `,`, + `Topic:` + fmt.Sprintf("%v", this.Topic) + `,`, `}`, }, "") return s @@ -17634,6 +20260,7 @@ func (this *SyncOperationResult) String() string { `Source:` + strings.Replace(strings.Replace(this.Source.String(), "ApplicationSource", "ApplicationSource", 1), `&`, ``, 1) + `,`, `Sources:` + repeatedStringForSources + `,`, `Revisions:` + fmt.Sprintf("%v", this.Revisions) + `,`, + `ManagedNamespaceMetadata:` + strings.Replace(this.ManagedNamespaceMetadata.String(), "ManagedNamespaceMetadata", "ManagedNamespaceMetadata", 1) + `,`, `}`, }, "") return s @@ -17738,6 +20365,17 @@ func (this *TLSClientConfig) String() string { }, "") return s } +func (this *TagFilter) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&TagFilter{`, + `Key:` + fmt.Sprintf("%v", this.Key) + `,`, + `Value:` + fmt.Sprintf("%v", this.Value) + `,`, + `}`, + }, "") + return s +} func valueToStringGenerated(v interface{}) string { rv := reflect.ValueOf(v) if rv.IsNil() { @@ -17839,6 +20477,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:]) @@ -19523,6 +22193,120 @@ func (m *ApplicationMatchExpression) Unmarshal(dAtA []byte) error { } return nil } +func (m *ApplicationPreservedFields) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ApplicationPreservedFields: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ApplicationPreservedFields: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Annotations", 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.Annotations = append(m.Annotations, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", 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.Labels = append(m.Labels, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ApplicationSet) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -19801,7 +22585,7 @@ func (m *ApplicationSetApplicationStatus) Unmarshal(dAtA []byte) error { } m.Message = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 5: + case 4: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) } @@ -19833,6 +22617,38 @@ func (m *ApplicationSetApplicationStatus) Unmarshal(dAtA []byte) error { } m.Status = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Step", 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.Step = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -20421,6 +23237,42 @@ func (m *ApplicationSetGenerator) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Plugin", 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 m.Plugin == nil { + m.Plugin = &PluginGenerator{} + } + if err := m.Plugin.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -20912,6 +23764,188 @@ func (m *ApplicationSetNestedGenerator) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Plugin", 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 m.Plugin == nil { + m.Plugin = &PluginGenerator{} + } + if err := m.Plugin.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ApplicationSetResourceIgnoreDifferences) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ApplicationSetResourceIgnoreDifferences: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ApplicationSetResourceIgnoreDifferences: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", 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.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field JSONPointers", 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.JSONPointers = append(m.JSONPointers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field JQPathExpressions", 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.JQPathExpressions = append(m.JQPathExpressions, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -21325,6 +24359,161 @@ func (m *ApplicationSetSpec) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PreservedFields", 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 m.PreservedFields == nil { + m.PreservedFields = &ApplicationPreservedFields{} + } + if err := m.PreservedFields.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GoTemplateOptions", 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.GoTemplateOptions = append(m.GoTemplateOptions, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ApplyNestedSelectors", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ApplyNestedSelectors = bool(v != 0) + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IgnoreApplicationDifferences", 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 + } + m.IgnoreApplicationDifferences = append(m.IgnoreApplicationDifferences, ApplicationSetResourceIgnoreDifferences{}) + if err := m.IgnoreApplicationDifferences[len(m.IgnoreApplicationDifferences)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + 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:]) @@ -21631,6 +24820,39 @@ func (m *ApplicationSetSyncPolicy) Unmarshal(dAtA []byte) error { } } m.PreserveResourcesOnDeletion = bool(v != 0) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ApplicationsSync", 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 := ApplicationsSyncPolicy(dAtA[iNdEx:postIndex]) + m.ApplicationsSync = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -22413,155 +25635,9 @@ func (m *ApplicationSetTerminalGenerator) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenerated(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ApplicationSource) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ApplicationSource: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ApplicationSource: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RepoURL", 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.RepoURL = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Path", 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.Path = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TargetRevision", 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.TargetRevision = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex case 7: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Helm", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Plugin", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -22588,88 +25664,306 @@ func (m *ApplicationSource) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Helm == nil { - m.Helm = &ApplicationSourceHelm{} + if m.Plugin == nil { + m.Plugin = &PluginGenerator{} } - if err := m.Helm.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Plugin.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 8: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Kustomize", 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 m.Kustomize == nil { - m.Kustomize = &ApplicationSourceKustomize{} - } - if err := m.Kustomize.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 10: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Directory", 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 m.Directory == nil { - m.Directory = &ApplicationSourceDirectory{} - } - if err := m.Directory.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 11: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Plugin", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Selector", 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 m.Selector == nil { + m.Selector = &v1.LabelSelector{} + } + if err := m.Selector.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ApplicationSource) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ApplicationSource: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ApplicationSource: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RepoURL", 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.RepoURL = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Path", 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.Path = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TargetRevision", 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.TargetRevision = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Helm", 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 m.Helm == nil { + m.Helm = &ApplicationSourceHelm{} + } + if err := m.Helm.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Kustomize", 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 m.Kustomize == nil { + m.Kustomize = &ApplicationSourceKustomize{} + } + if err := m.Kustomize.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Directory", 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 m.Directory == nil { + m.Directory = &ApplicationSourceDirectory{} + } + if err := m.Directory.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Plugin", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -23240,6 +26534,42 @@ func (m *ApplicationSourceHelm) Unmarshal(dAtA []byte) error { } } m.SkipCrds = bool(v != 0) + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValuesObject", 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 m.ValuesObject == nil { + m.ValuesObject = &runtime.RawExtension{} + } + if err := m.ValuesObject.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -23862,6 +27192,178 @@ func (m *ApplicationSourceKustomize) Unmarshal(dAtA []byte) error { } } m.ForceCommonAnnotations = bool(v != 0) + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", 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.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CommonAnnotationsEnvsubst", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CommonAnnotationsEnvsubst = bool(v != 0) + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Replicas", 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 + } + m.Replicas = append(m.Replicas, KustomizeReplica{}) + if err := m.Replicas[len(m.Replicas)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Patches", 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 + } + m.Patches = append(m.Patches, KustomizePatch{}) + if err := m.Patches[len(m.Patches)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + 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 + case 14: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LabelWithoutSelector", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.LabelWithoutSelector = bool(v != 0) default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -24096,7 +27598,7 @@ func (m *ApplicationSourcePluginParameter) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Map", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field OptionalMap", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -24123,109 +27625,18 @@ func (m *ApplicationSourcePluginParameter) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Map == nil { - m.Map = make(map[string]string) + if m.OptionalMap == nil { + m.OptionalMap = &OptionalMap{} } - var mapkey string - var mapvalue string - for iNdEx < postIndex { - entryPreIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - if fieldNum == 1 { - var stringLenmapkey uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLenmapkey |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLenmapkey := int(stringLenmapkey) - if intStringLenmapkey < 0 { - return ErrInvalidLengthGenerated - } - postStringIndexmapkey := iNdEx + intStringLenmapkey - if postStringIndexmapkey < 0 { - return ErrInvalidLengthGenerated - } - if postStringIndexmapkey > l { - return io.ErrUnexpectedEOF - } - mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) - iNdEx = postStringIndexmapkey - } else if fieldNum == 2 { - var stringLenmapvalue uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLenmapvalue |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLenmapvalue := int(stringLenmapvalue) - if intStringLenmapvalue < 0 { - return ErrInvalidLengthGenerated - } - postStringIndexmapvalue := iNdEx + intStringLenmapvalue - if postStringIndexmapvalue < 0 { - return ErrInvalidLengthGenerated - } - if postStringIndexmapvalue > l { - return io.ErrUnexpectedEOF - } - mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) - iNdEx = postStringIndexmapvalue - } else { - iNdEx = entryPreIndex - skippy, err := skipGenerated(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) > postIndex { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } + if err := m.OptionalMap.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - m.Map[mapkey] = mapvalue iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Array", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field OptionalArray", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -24235,23 +27646,27 @@ func (m *ApplicationSourcePluginParameter) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Array = append(m.Array, string(dAtA[iNdEx:postIndex])) + if m.OptionalArray == nil { + m.OptionalArray = &OptionalArray{} + } + if err := m.OptionalArray.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 5: if wireType != 2 { @@ -25050,6 +28465,38 @@ func (m *ApplicationStatus) Unmarshal(dAtA []byte) error { } m.SourceTypes = append(m.SourceTypes, ApplicationSourceType(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ControllerNamespace", 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.ControllerNamespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -25704,7 +29151,7 @@ func (m *BasicAuthBitbucketServer) Unmarshal(dAtA []byte) error { } return nil } -func (m *Cluster) Unmarshal(dAtA []byte) error { +func (m *BearerTokenBitbucketCloud) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -25727,17 +29174,17 @@ func (m *Cluster) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Cluster: wiretype end group for non-group") + return fmt.Errorf("proto: BearerTokenBitbucketCloud: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Cluster: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: BearerTokenBitbucketCloud: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Server", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field TokenRef", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -25747,27 +29194,81 @@ func (m *Cluster) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Server = string(dAtA[iNdEx:postIndex]) + if m.TokenRef == nil { + m.TokenRef = &SecretRef{} + } + if err := m.TokenRef.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 2: + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ChartDetails) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ChartDetails: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ChartDetails: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -25795,13 +29296,13 @@ func (m *Cluster) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Name = string(dAtA[iNdEx:postIndex]) + m.Description = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Config", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Home", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -25811,30 +29312,29 @@ func (m *Cluster) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Config.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Home = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 4: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ConnectionState", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Maintainers", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -25844,28 +29344,77 @@ func (m *Cluster) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ConnectionState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Maintainers = append(m.Maintainers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { return err } - iNdEx = postIndex - case 5: + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Cluster) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Cluster: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Cluster: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ServerVersion", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Server", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -25893,11 +29442,11 @@ func (m *Cluster) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ServerVersion = string(dAtA[iNdEx:postIndex]) + m.Server = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 6: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Namespaces", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -25925,11 +29474,11 @@ func (m *Cluster) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Namespaces = append(m.Namespaces, string(dAtA[iNdEx:postIndex])) + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 7: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RefreshRequestedAt", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Config", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -25956,16 +29505,13 @@ func (m *Cluster) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.RefreshRequestedAt == nil { - m.RefreshRequestedAt = &v1.Time{} - } - if err := m.RefreshRequestedAt.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Config.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 8: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionState", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -25992,15 +29538,15 @@ func (m *Cluster) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.ConnectionState.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 9: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Shard", wireType) + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ServerVersion", wireType) } - var v int64 + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -26010,35 +29556,27 @@ func (m *Cluster) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int64(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - m.Shard = &v - case 10: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ClusterResources", wireType) + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated } - m.ClusterResources = bool(v != 0) - case 11: + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ServerVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Namespaces", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -26066,11 +29604,152 @@ func (m *Cluster) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Project = string(dAtA[iNdEx:postIndex]) + m.Namespaces = append(m.Namespaces, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 12: + case 7: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RefreshRequestedAt", 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 m.RefreshRequestedAt == nil { + m.RefreshRequestedAt = &v1.Time{} + } + if err := m.RefreshRequestedAt.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Info", 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.Info.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Shard", wireType) + } + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Shard = &v + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ClusterResources", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ClusterResources = bool(v != 0) + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", 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.Project = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -27520,93 +31199,11 @@ func (m *ComparedTo) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenerated(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ComponentParameter) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ComponentParameter: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ComponentParameter: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Component", 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.Component = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field IgnoreDifferences", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -27616,55 +31213,171 @@ func (m *ComponentParameter) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Name = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Value", 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.IgnoreDifferences = append(m.IgnoreDifferences, ResourceIgnoreDifferences{}) + if err := m.IgnoreDifferences[len(m.IgnoreDifferences)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - m.Value = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ComponentParameter) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ComponentParameter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ComponentParameter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Component", 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.Component = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", 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.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", 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.Value = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -29184,6 +32897,133 @@ func (m *GitGenerator) Unmarshal(dAtA []byte) error { } m.PathParamPrefix = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Values", 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 m.Values == nil { + m.Values = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Values[mapkey] = mapvalue + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -30976,7 +34816,7 @@ func (m *KnownTypeField) Unmarshal(dAtA []byte) error { } return nil } -func (m *KustomizeOptions) Unmarshal(dAtA []byte) error { +func (m *KustomizeGvk) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -30999,15 +34839,15 @@ func (m *KustomizeOptions) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: KustomizeOptions: wiretype end group for non-group") + return fmt.Errorf("proto: KustomizeGvk: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: KustomizeOptions: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: KustomizeGvk: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BuildOptions", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Group", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -31035,11 +34875,11 @@ func (m *KustomizeOptions) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.BuildOptions = string(dAtA[iNdEx:postIndex]) + m.Group = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BinaryPath", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -31067,7 +34907,39 @@ func (m *KustomizeOptions) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.BinaryPath = string(dAtA[iNdEx:postIndex]) + m.Version = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Kind", 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.Kind = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -31090,7 +34962,7 @@ func (m *KustomizeOptions) Unmarshal(dAtA []byte) error { } return nil } -func (m *ListGenerator) Unmarshal(dAtA []byte) error { +func (m *KustomizeOptions) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -31113,17 +34985,17 @@ func (m *ListGenerator) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ListGenerator: wiretype end group for non-group") + return fmt.Errorf("proto: KustomizeOptions: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ListGenerator: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: KustomizeOptions: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Elements", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field BuildOptions", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -31133,31 +35005,29 @@ func (m *ListGenerator) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Elements = append(m.Elements, v11.JSON{}) - if err := m.Elements[len(m.Elements)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.BuildOptions = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Template", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field BinaryPath", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -31167,24 +35037,23 @@ func (m *ListGenerator) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Template.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.BinaryPath = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -31207,7 +35076,7 @@ func (m *ListGenerator) Unmarshal(dAtA []byte) error { } return nil } -func (m *ManagedNamespaceMetadata) Unmarshal(dAtA []byte) error { +func (m *KustomizePatch) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -31230,15 +35099,79 @@ func (m *ManagedNamespaceMetadata) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ManagedNamespaceMetadata: wiretype end group for non-group") + return fmt.Errorf("proto: KustomizePatch: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ManagedNamespaceMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: KustomizePatch: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Path", 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.Path = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Patch", 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.Patch = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Target", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -31265,107 +35198,16 @@ func (m *ManagedNamespaceMetadata) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Labels == nil { - m.Labels = make(map[string]string) + if m.Target == nil { + m.Target = &KustomizeSelector{} } - var mapkey string - var mapvalue string - for iNdEx < postIndex { - entryPreIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - if fieldNum == 1 { - var stringLenmapkey uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLenmapkey |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLenmapkey := int(stringLenmapkey) - if intStringLenmapkey < 0 { - return ErrInvalidLengthGenerated - } - postStringIndexmapkey := iNdEx + intStringLenmapkey - if postStringIndexmapkey < 0 { - return ErrInvalidLengthGenerated - } - if postStringIndexmapkey > l { - return io.ErrUnexpectedEOF - } - mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) - iNdEx = postStringIndexmapkey - } else if fieldNum == 2 { - var stringLenmapvalue uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLenmapvalue |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLenmapvalue := int(stringLenmapvalue) - if intStringLenmapvalue < 0 { - return ErrInvalidLengthGenerated - } - postStringIndexmapvalue := iNdEx + intStringLenmapvalue - if postStringIndexmapvalue < 0 { - return ErrInvalidLengthGenerated - } - if postStringIndexmapvalue > l { - return io.ErrUnexpectedEOF - } - mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) - iNdEx = postStringIndexmapvalue - } else { - iNdEx = entryPreIndex - skippy, err := skipGenerated(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) > postIndex { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } + if err := m.Target.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } - m.Labels[mapkey] = mapvalue iNdEx = postIndex - case 2: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Annotations", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Options", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -31392,11 +35234,11 @@ func (m *ManagedNamespaceMetadata) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Annotations == nil { - m.Annotations = make(map[string]string) + if m.Options == nil { + m.Options = make(map[string]bool) } var mapkey string - var mapvalue string + var mapvalue bool for iNdEx < postIndex { entryPreIndex := iNdEx var wire uint64 @@ -31445,7 +35287,7 @@ func (m *ManagedNamespaceMetadata) Unmarshal(dAtA []byte) error { mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) iNdEx = postStringIndexmapkey } else if fieldNum == 2 { - var stringLenmapvalue uint64 + var mapvaluetemp int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -31455,24 +35297,12 @@ func (m *ManagedNamespaceMetadata) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLenmapvalue |= uint64(b&0x7F) << shift + mapvaluetemp |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLenmapvalue := int(stringLenmapvalue) - if intStringLenmapvalue < 0 { - return ErrInvalidLengthGenerated - } - postStringIndexmapvalue := iNdEx + intStringLenmapvalue - if postStringIndexmapvalue < 0 { - return ErrInvalidLengthGenerated - } - if postStringIndexmapvalue > l { - return io.ErrUnexpectedEOF - } - mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) - iNdEx = postStringIndexmapvalue + mapvalue = bool(mapvaluetemp != 0) } else { iNdEx = entryPreIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -31488,7 +35318,7 @@ func (m *ManagedNamespaceMetadata) Unmarshal(dAtA []byte) error { iNdEx += skippy } } - m.Annotations[mapkey] = mapvalue + m.Options[mapkey] = mapvalue iNdEx = postIndex default: iNdEx = preIndex @@ -31511,7 +35341,7 @@ func (m *ManagedNamespaceMetadata) Unmarshal(dAtA []byte) error { } return nil } -func (m *MatrixGenerator) Unmarshal(dAtA []byte) error { +func (m *KustomizeReplica) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -31534,17 +35364,17 @@ func (m *MatrixGenerator) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MatrixGenerator: wiretype end group for non-group") + return fmt.Errorf("proto: KustomizeReplica: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MatrixGenerator: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: KustomizeReplica: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Generators", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -31554,29 +35384,27 @@ func (m *MatrixGenerator) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Generators = append(m.Generators, ApplicationSetNestedGenerator{}) - if err := m.Generators[len(m.Generators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Template", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Count", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -31603,7 +35431,7 @@ func (m *MatrixGenerator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Template.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Count.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -31628,7 +35456,7 @@ func (m *MatrixGenerator) Unmarshal(dAtA []byte) error { } return nil } -func (m *MergeGenerator) Unmarshal(dAtA []byte) error { +func (m *KustomizeResId) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -31651,15 +35479,15 @@ func (m *MergeGenerator) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MergeGenerator: wiretype end group for non-group") + return fmt.Errorf("proto: KustomizeResId: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MergeGenerator: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: KustomizeResId: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Generators", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field KustomizeGvk", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -31686,14 +35514,13 @@ func (m *MergeGenerator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Generators = append(m.Generators, ApplicationSetNestedGenerator{}) - if err := m.Generators[len(m.Generators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.KustomizeGvk.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MergeKeys", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -31721,13 +35548,13 @@ func (m *MergeGenerator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.MergeKeys = append(m.MergeKeys, string(dAtA[iNdEx:postIndex])) + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Template", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -31737,24 +35564,23 @@ func (m *MergeGenerator) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Template.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Namespace = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -31777,7 +35603,7 @@ func (m *MergeGenerator) Unmarshal(dAtA []byte) error { } return nil } -func (m *NestedMatrixGenerator) Unmarshal(dAtA []byte) error { +func (m *KustomizeSelector) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -31800,15 +35626,15 @@ func (m *NestedMatrixGenerator) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: NestedMatrixGenerator: wiretype end group for non-group") + return fmt.Errorf("proto: KustomizeSelector: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: NestedMatrixGenerator: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: KustomizeSelector: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Generators", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field KustomizeResId", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -31835,66 +35661,15 @@ func (m *NestedMatrixGenerator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Generators = append(m.Generators, ApplicationSetTerminalGenerator{}) - if err := m.Generators[len(m.Generators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.KustomizeResId.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenerated(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *NestedMergeGenerator) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: NestedMergeGenerator: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: NestedMergeGenerator: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Generators", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AnnotationSelector", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -31904,29 +35679,27 @@ func (m *NestedMergeGenerator) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Generators = append(m.Generators, ApplicationSetTerminalGenerator{}) - if err := m.Generators[len(m.Generators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.AnnotationSelector = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MergeKeys", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LabelSelector", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -31954,7 +35727,7 @@ func (m *NestedMergeGenerator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.MergeKeys = append(m.MergeKeys, string(dAtA[iNdEx:postIndex])) + m.LabelSelector = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -31977,7 +35750,7 @@ func (m *NestedMergeGenerator) Unmarshal(dAtA []byte) error { } return nil } -func (m *Operation) Unmarshal(dAtA []byte) error { +func (m *ListGenerator) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -32000,15 +35773,15 @@ func (m *Operation) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Operation: wiretype end group for non-group") + return fmt.Errorf("proto: ListGenerator: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Operation: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ListGenerator: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sync", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Elements", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -32035,16 +35808,14 @@ func (m *Operation) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Sync == nil { - m.Sync = &SyncOperation{} - } - if err := m.Sync.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Elements = append(m.Elements, v11.JSON{}) + if err := m.Elements[len(m.Elements)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field InitiatedBy", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Template", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -32071,13 +35842,95 @@ func (m *Operation) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.InitiatedBy.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Template.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ElementsYaml", 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.ElementsYaml = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ManagedNamespaceMetadata) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ManagedNamespaceMetadata: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ManagedNamespaceMetadata: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Labels", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -32104,14 +35957,107 @@ func (m *Operation) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Info = append(m.Info, &Info{}) - if err := m.Info[len(m.Info)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + if m.Labels == nil { + m.Labels = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } } + m.Labels[mapkey] = mapvalue iNdEx = postIndex - case 4: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Retry", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Annotations", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -32138,9 +36084,103 @@ func (m *Operation) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Retry.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + if m.Annotations == nil { + m.Annotations = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } } + m.Annotations[mapkey] = mapvalue iNdEx = postIndex default: iNdEx = preIndex @@ -32163,7 +36203,7 @@ func (m *Operation) Unmarshal(dAtA []byte) error { } return nil } -func (m *OperationInitiator) Unmarshal(dAtA []byte) error { +func (m *MatrixGenerator) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -32186,17 +36226,17 @@ func (m *OperationInitiator) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: OperationInitiator: wiretype end group for non-group") + return fmt.Errorf("proto: MatrixGenerator: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: OperationInitiator: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MatrixGenerator: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Username", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Generators", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -32206,29 +36246,31 @@ func (m *OperationInitiator) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Username = string(dAtA[iNdEx:postIndex]) + m.Generators = append(m.Generators, ApplicationSetNestedGenerator{}) + if err := m.Generators[len(m.Generators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Automated", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Template", wireType) } - var v int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -32238,12 +36280,25 @@ func (m *OperationInitiator) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - m.Automated = bool(v != 0) + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Template.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -32265,7 +36320,7 @@ func (m *OperationInitiator) Unmarshal(dAtA []byte) error { } return nil } -func (m *OperationState) Unmarshal(dAtA []byte) error { +func (m *MergeGenerator) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -32288,15 +36343,15 @@ func (m *OperationState) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: OperationState: wiretype end group for non-group") + return fmt.Errorf("proto: MergeGenerator: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: OperationState: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MergeGenerator: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Operation", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Generators", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -32323,13 +36378,14 @@ func (m *OperationState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Operation.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Generators = append(m.Generators, ApplicationSetNestedGenerator{}) + if err := m.Generators[len(m.Generators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Phase", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MergeKeys", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -32357,43 +36413,11 @@ func (m *OperationState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Phase = github_com_argoproj_gitops_engine_pkg_sync_common.OperationPhase(dAtA[iNdEx:postIndex]) + m.MergeKeys = append(m.MergeKeys, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Message", 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.Message = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SyncResult", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Template", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -32420,18 +36444,65 @@ func (m *OperationState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.SyncResult == nil { - m.SyncResult = &SyncOperationResult{} - } - if err := m.SyncResult.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Template.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field StartedAt", wireType) + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err } - var msglen int + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NestedMatrixGenerator) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: NestedMatrixGenerator: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NestedMatrixGenerator: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Generators", wireType) + } + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -32456,13 +36527,64 @@ func (m *OperationState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.StartedAt.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Generators = append(m.Generators, ApplicationSetTerminalGenerator{}) + if err := m.Generators[len(m.Generators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 7: + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NestedMergeGenerator) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: NestedMergeGenerator: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NestedMergeGenerator: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field FinishedAt", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Generators", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -32489,18 +36611,16 @@ func (m *OperationState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.FinishedAt == nil { - m.FinishedAt = &v1.Time{} - } - if err := m.FinishedAt.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Generators = append(m.Generators, ApplicationSetTerminalGenerator{}) + if err := m.Generators[len(m.Generators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 8: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field RetryCount", wireType) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MergeKeys", wireType) } - m.RetryCount = 0 + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -32510,11 +36630,24 @@ func (m *OperationState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.RetryCount |= int64(b&0x7F) << shift + 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.MergeKeys = append(m.MergeKeys, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -32536,7 +36669,7 @@ func (m *OperationState) Unmarshal(dAtA []byte) error { } return nil } -func (m *OrphanedResourceKey) Unmarshal(dAtA []byte) error { +func (m *Operation) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -32559,17 +36692,17 @@ func (m *OrphanedResourceKey) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: OrphanedResourceKey: wiretype end group for non-group") + return fmt.Errorf("proto: Operation: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: OrphanedResourceKey: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Operation: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Group", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Sync", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -32579,29 +36712,33 @@ func (m *OrphanedResourceKey) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Group = string(dAtA[iNdEx:postIndex]) + if m.Sync == nil { + m.Sync = &SyncOperation{} + } + if err := m.Sync.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field InitiatedBy", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -32611,29 +36748,30 @@ func (m *OrphanedResourceKey) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Kind = string(dAtA[iNdEx:postIndex]) + if err := m.InitiatedBy.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Info", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -32643,23 +36781,58 @@ func (m *OrphanedResourceKey) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Name = string(dAtA[iNdEx:postIndex]) + m.Info = append(m.Info, &Info{}) + if err := m.Info[len(m.Info)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Retry", 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.Retry.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex @@ -32682,7 +36855,7 @@ func (m *OrphanedResourceKey) Unmarshal(dAtA []byte) error { } return nil } -func (m *OrphanedResourcesMonitorSettings) Unmarshal(dAtA []byte) error { +func (m *OperationInitiator) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -32705,17 +36878,17 @@ func (m *OrphanedResourcesMonitorSettings) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: OrphanedResourcesMonitorSettings: wiretype end group for non-group") + return fmt.Errorf("proto: OperationInitiator: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: OrphanedResourcesMonitorSettings: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: OperationInitiator: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Warn", wireType) + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Username", wireType) } - var v int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -32725,18 +36898,29 @@ func (m *OrphanedResourcesMonitorSettings) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - v |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - b := bool(v != 0) - m.Warn = &b + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Username = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Ignore", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Automated", wireType) } - var msglen int + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -32746,26 +36930,12 @@ func (m *OrphanedResourcesMonitorSettings) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + v |= 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 - } - m.Ignore = append(m.Ignore, OrphanedResourceKey{}) - if err := m.Ignore[len(m.Ignore)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex + m.Automated = bool(v != 0) default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -32787,7 +36957,7 @@ func (m *OrphanedResourcesMonitorSettings) Unmarshal(dAtA []byte) error { } return nil } -func (m *OverrideIgnoreDiff) Unmarshal(dAtA []byte) error { +func (m *OperationState) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -32810,17 +36980,17 @@ func (m *OverrideIgnoreDiff) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: OverrideIgnoreDiff: wiretype end group for non-group") + return fmt.Errorf("proto: OperationState: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: OverrideIgnoreDiff: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: OperationState: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field JSONPointers", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Operation", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -32830,27 +37000,28 @@ func (m *OverrideIgnoreDiff) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.JSONPointers = append(m.JSONPointers, string(dAtA[iNdEx:postIndex])) + if err := m.Operation.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field JQPathExpressions", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Phase", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -32878,11 +37049,11 @@ func (m *OverrideIgnoreDiff) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.JQPathExpressions = append(m.JQPathExpressions, string(dAtA[iNdEx:postIndex])) + m.Phase = github_com_argoproj_gitops_engine_pkg_sync_common.OperationPhase(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ManagedFieldsManagers", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Message", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -32910,8 +37081,132 @@ func (m *OverrideIgnoreDiff) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ManagedFieldsManagers = append(m.ManagedFieldsManagers, string(dAtA[iNdEx:postIndex])) + m.Message = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SyncResult", 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 m.SyncResult == nil { + m.SyncResult = &SyncOperationResult{} + } + if err := m.SyncResult.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StartedAt", 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.StartedAt.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FinishedAt", 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 m.FinishedAt == nil { + m.FinishedAt = &v1.Time{} + } + if err := m.FinishedAt.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RetryCount", wireType) + } + m.RetryCount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RetryCount |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -32933,7 +37228,7 @@ func (m *OverrideIgnoreDiff) Unmarshal(dAtA []byte) error { } return nil } -func (m *ProjectRole) Unmarshal(dAtA []byte) error { +func (m *OptionalArray) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -32956,15 +37251,15 @@ func (m *ProjectRole) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ProjectRole: wiretype end group for non-group") + return fmt.Errorf("proto: OptionalArray: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ProjectRole: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: OptionalArray: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Array", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -32992,13 +37287,63 @@ func (m *ProjectRole) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Name = string(dAtA[iNdEx:postIndex]) + m.Array = append(m.Array, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - case 2: + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *OptionalMap) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: OptionalMap: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OptionalMap: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Map", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -33008,37 +37353,1701 @@ func (m *ProjectRole) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Description = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Policies", wireType) + if m.Map == nil { + m.Map = make(map[string]string) } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Map[mapkey] = mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *OrphanedResourceKey) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: OrphanedResourceKey: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OrphanedResourceKey: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Group", 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.Group = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Kind", 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.Kind = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", 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.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *OrphanedResourcesMonitorSettings) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: OrphanedResourcesMonitorSettings: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OrphanedResourcesMonitorSettings: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Warn", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.Warn = &b + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Ignore", 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 + } + m.Ignore = append(m.Ignore, OrphanedResourceKey{}) + if err := m.Ignore[len(m.Ignore)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *OverrideIgnoreDiff) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: OverrideIgnoreDiff: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OverrideIgnoreDiff: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field JSONPointers", 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.JSONPointers = append(m.JSONPointers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field JQPathExpressions", 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.JQPathExpressions = append(m.JQPathExpressions, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ManagedFieldsManagers", 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.ManagedFieldsManagers = append(m.ManagedFieldsManagers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PluginConfigMapRef) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PluginConfigMapRef: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PluginConfigMapRef: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", 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.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PluginGenerator) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PluginGenerator: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PluginGenerator: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConfigMapRef", 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.ConfigMapRef.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Input", 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.Input.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RequeueAfterSeconds", wireType) + } + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.RequeueAfterSeconds = &v + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Template", 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.Template.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Values", 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 m.Values == nil { + m.Values = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Values[mapkey] = mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PluginInput) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PluginInput: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PluginInput: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Parameters", 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 m.Parameters == nil { + m.Parameters = make(PluginParameters) + } + var mapkey string + mapvalue := &v11.JSON{} + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var mapmsglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapmsglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if mapmsglen < 0 { + return ErrInvalidLengthGenerated + } + postmsgIndex := iNdEx + mapmsglen + if postmsgIndex < 0 { + return ErrInvalidLengthGenerated + } + if postmsgIndex > l { + return io.ErrUnexpectedEOF + } + mapvalue = &v11.JSON{} + if err := mapvalue.Unmarshal(dAtA[iNdEx:postmsgIndex]); err != nil { + return err + } + iNdEx = postmsgIndex + } else { + iNdEx = entryPreIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Parameters[mapkey] = *mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ProjectRole) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ProjectRole: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ProjectRole: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", 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.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", 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.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Policies", 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.Policies = append(m.Policies, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field JWTTokens", 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 + } + m.JWTTokens = append(m.JWTTokens, JWTToken{}) + if err := m.JWTTokens[len(m.JWTTokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Groups", 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.Groups = append(m.Groups, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PullRequestGenerator) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PullRequestGenerator: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PullRequestGenerator: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Github", 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 m.Github == nil { + m.Github = &PullRequestGeneratorGithub{} + } + if err := m.Github.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GitLab", 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 m.GitLab == nil { + m.GitLab = &PullRequestGeneratorGitLab{} + } + if err := m.GitLab.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Gitea", 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 m.Gitea == nil { + m.Gitea = &PullRequestGeneratorGitea{} + } + if err := m.Gitea.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field BitbucketServer", 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 m.BitbucketServer == nil { + m.BitbucketServer = &PullRequestGeneratorBitbucketServer{} + } + if err := m.BitbucketServer.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Filters", 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 + } + m.Filters = append(m.Filters, PullRequestGeneratorFilter{}) + if err := m.Filters[len(m.Filters)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RequeueAfterSeconds", wireType) + } + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.RequeueAfterSeconds = &v + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Template", 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.Template.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Bitbucket", 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 m.Bitbucket == nil { + m.Bitbucket = &PullRequestGeneratorBitbucket{} + } + if err := m.Bitbucket.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AzureDevOps", 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 m.AzureDevOps == nil { + m.AzureDevOps = &PullRequestGeneratorAzureDevOps{} + } + if err := m.AzureDevOps.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PullRequestGeneratorAzureDevOps) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PullRequestGeneratorAzureDevOps: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PullRequestGeneratorAzureDevOps: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Organization", 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 { @@ -33056,11 +39065,107 @@ func (m *ProjectRole) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Policies = append(m.Policies, string(dAtA[iNdEx:postIndex])) + m.Organization = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Project", 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.Project = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Repo", 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.Repo = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field JWTTokens", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field API", 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.API = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenRef", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -33087,14 +39192,130 @@ func (m *ProjectRole) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.JWTTokens = append(m.JWTTokens, JWTToken{}) - if err := m.JWTTokens[len(m.JWTTokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if m.TokenRef == nil { + m.TokenRef = &SecretRef{} + } + if err := m.TokenRef.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 5: + case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Groups", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Labels", 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.Labels = append(m.Labels, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PullRequestGeneratorBitbucket) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PullRequestGeneratorBitbucket: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PullRequestGeneratorBitbucket: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Owner", 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.Owner = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Repo", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -33122,135 +39343,13 @@ func (m *ProjectRole) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Groups = append(m.Groups, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenerated(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *PullRequestGenerator) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: PullRequestGenerator: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: PullRequestGenerator: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Github", 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 m.Github == nil { - m.Github = &PullRequestGeneratorGithub{} - } - if err := m.Github.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field GitLab", 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 m.GitLab == nil { - m.GitLab = &PullRequestGeneratorGitLab{} - } - if err := m.GitLab.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Repo = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Gitea", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field API", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -33260,31 +39359,27 @@ func (m *PullRequestGenerator) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - if m.Gitea == nil { - m.Gitea = &PullRequestGeneratorGitea{} - } - if err := m.Gitea.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.API = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BitbucketServer", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field BasicAuth", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -33311,16 +39406,16 @@ func (m *PullRequestGenerator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.BitbucketServer == nil { - m.BitbucketServer = &PullRequestGeneratorBitbucketServer{} + if m.BasicAuth == nil { + m.BasicAuth = &BasicAuthBitbucketServer{} } - if err := m.BitbucketServer.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.BasicAuth.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Filters", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field BearerToken", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -33347,61 +39442,10 @@ func (m *PullRequestGenerator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Filters = append(m.Filters, PullRequestGeneratorFilter{}) - if err := m.Filters[len(m.Filters)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field RequeueAfterSeconds", wireType) - } - var v int64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.RequeueAfterSeconds = &v - case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Template", 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 m.BearerToken == nil { + m.BearerToken = &BearerTokenBitbucketCloud{} } - if err := m.Template.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.BearerToken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex @@ -33670,6 +39714,39 @@ func (m *PullRequestGeneratorFilter) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.BranchMatch = &s iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TargetBranchMatch", 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.TargetBranchMatch = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -33884,6 +39961,26 @@ func (m *PullRequestGeneratorGitLab) Unmarshal(dAtA []byte) error { } m.PullRequestState = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Insecure", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Insecure = bool(v != 0) default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -34939,6 +41036,26 @@ func (m *RepoCreds) Unmarshal(dAtA []byte) error { } m.Proxy = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 20: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ForceHttpBasicAuth", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ForceHttpBasicAuth = bool(v != 0) default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -35693,6 +41810,26 @@ func (m *Repository) Unmarshal(dAtA []byte) error { } m.GCPServiceAccountKey = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 22: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ForceHttpBasicAuth", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ForceHttpBasicAuth = bool(v != 0) default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -35926,7 +42063,241 @@ func (m *RepositoryCertificate) Unmarshal(dAtA []byte) error { } return nil } -func (m *RepositoryCertificateList) Unmarshal(dAtA []byte) error { +func (m *RepositoryCertificateList) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RepositoryCertificateList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RepositoryCertificateList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", 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.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Items", 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 + } + m.Items = append(m.Items, RepositoryCertificate{}) + if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RepositoryList) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RepositoryList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RepositoryList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", 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.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Items", 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 + } + m.Items = append(m.Items, &Repository{}) + if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ResourceAction) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -35949,17 +42320,17 @@ func (m *RepositoryCertificateList) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: RepositoryCertificateList: wiretype end group for non-group") + return fmt.Errorf("proto: ResourceAction: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: RepositoryCertificateList: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ResourceAction: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -35969,112 +42340,27 @@ func (m *RepositoryCertificateList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Items", 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 - } - m.Items = append(m.Items, RepositoryCertificate{}) - if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenerated(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *RepositoryList) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: RepositoryList: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: RepositoryList: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ListMeta", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -36101,15 +42387,16 @@ func (m *RepositoryList) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.ListMeta.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Params = append(m.Params, ResourceActionParam{}) + if err := m.Params[len(m.Params)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Items", wireType) + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Disabled", wireType) } - var msglen int + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -36119,79 +42406,15 @@ func (m *RepositoryList) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + v |= 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 - } - m.Items = append(m.Items, &Repository{}) - if err := m.Items[len(m.Items)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenerated(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ResourceAction) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ResourceAction: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ResourceAction: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + m.Disabled = bool(v != 0) + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field IconClass", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -36219,13 +42442,13 @@ func (m *ResourceAction) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Name = string(dAtA[iNdEx:postIndex]) + m.IconClass = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field DisplayName", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -36235,46 +42458,24 @@ func (m *ResourceAction) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenerated } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenerated } if postIndex > l { return io.ErrUnexpectedEOF } - m.Params = append(m.Params, ResourceActionParam{}) - if err := m.Params[len(m.Params)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.DisplayName = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Disabled", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Disabled = bool(v != 0) default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -38295,6 +44496,39 @@ func (m *ResourceOverride) Unmarshal(dAtA []byte) error { } } m.UseOpenLibs = bool(v != 0) + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IgnoreResourceUpdates", 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.IgnoreResourceUpdates.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -39618,6 +45852,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:]) @@ -40159,33 +46426,377 @@ func (m *SCMProviderGenerator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CloneProtocol = string(dAtA[iNdEx:postIndex]) + m.CloneProtocol = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RequeueAfterSeconds", wireType) + } + var v int64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.RequeueAfterSeconds = &v + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Template", 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.Template.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Values", 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 m.Values == nil { + m.Values = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthGenerated + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthGenerated + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Values[mapkey] = mapvalue + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AWSCodeCommit", 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 m.AWSCodeCommit == nil { + m.AWSCodeCommit = &SCMProviderGeneratorAWSCodeCommit{} + } + if err := m.AWSCodeCommit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SCMProviderGeneratorAWSCodeCommit) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SCMProviderGeneratorAWSCodeCommit: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SCMProviderGeneratorAWSCodeCommit: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TagFilters", 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 + } + m.TagFilters = append(m.TagFilters, &TagFilter{}) + if err := m.TagFilters[len(m.TagFilters)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Role", 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.Role = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Region", 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.Region = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 9: + case 4: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field RequeueAfterSeconds", wireType) - } - var v int64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.RequeueAfterSeconds = &v - case 10: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Template", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AllBranches", wireType) } - var msglen int + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenerated @@ -40195,25 +46806,12 @@ func (m *SCMProviderGenerator) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + v |= 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.Template.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex + m.AllBranches = bool(v != 0) default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -41551,6 +48149,79 @@ func (m *SCMProviderGeneratorGitlab) Unmarshal(dAtA []byte) error { } } m.AllBranches = bool(v != 0) + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Insecure", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Insecure = bool(v != 0) + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IncludeSharedProjects", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + b := bool(v != 0) + m.IncludeSharedProjects = &b + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Topic", 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.Topic = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -42498,6 +49169,42 @@ func (m *SyncOperationResult) Unmarshal(dAtA []byte) error { } m.Revisions = append(m.Revisions, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ManagedNamespaceMetadata", 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 m.ManagedNamespaceMetadata == nil { + m.ManagedNamespaceMetadata = &ManagedNamespaceMetadata{} + } + if err := m.ManagedNamespaceMetadata.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -43771,6 +50478,120 @@ func (m *TLSClientConfig) Unmarshal(dAtA []byte) error { } return nil } +func (m *TagFilter) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TagFilter: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TagFilter: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", 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.Key = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", 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.Value = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipGenerated(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/pkg/apis/application/v1alpha1/generated.proto b/pkg/apis/application/v1alpha1/generated.proto index c7f3a766548e3..7a296f1e467fe 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: @@ -116,7 +119,7 @@ message Application { optional Operation operation = 4; } -// ApplicationCondition contains details about an application condition, which is usally an error or warning +// ApplicationCondition contains details about an application condition, which is usually an error or warning message ApplicationCondition { // Type is an application condition type optional string type = 1; @@ -130,14 +133,14 @@ message ApplicationCondition { // ApplicationDestination holds information about the application's destination message ApplicationDestination { - // Server specifies the URL of the target cluster and must be set to the Kubernetes control plane API + // Server specifies the URL of the target cluster's Kubernetes control plane API. This must be set if Name is not set. optional string server = 1; // Namespace specifies the target namespace for the application's resources. // The namespace will only be set for namespace-scoped resources that have not set a value for .metadata.namespace optional string namespace = 2; - // Name is an alternate way of specifying the target cluster by its symbolic name + // Name is an alternate way of specifying the target cluster by its symbolic name. This must be set if Server is not set. optional string name = 3; } @@ -157,6 +160,12 @@ message ApplicationMatchExpression { repeated string values = 3; } +message ApplicationPreservedFields { + repeated string annotations = 1; + + repeated string labels = 2; +} + // ApplicationSet is a set of Application resources // +genclient // +genclient:noStatus @@ -183,7 +192,10 @@ message ApplicationSetApplicationStatus { optional string message = 3; // Status contains the AppSet's perceived status of the managed Application resource: (Waiting, Pending, Progressing, Healthy) - optional string status = 5; + optional string status = 4; + + // Step tracks which step this Application should be updated in + optional string step = 5; } // ApplicationSetCondition contains details about an applicationset condition, which is usally an error or warning @@ -224,6 +236,8 @@ message ApplicationSetGenerator { // Selector allows to post-filter all generator. optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 9; + + optional PluginGenerator plugin = 10; } // ApplicationSetList contains a list of ApplicationSet @@ -258,6 +272,21 @@ message ApplicationSetNestedGenerator { // Selector allows to post-filter all generator. optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 9; + + optional PluginGenerator plugin = 10; +} + +// ApplicationSetResourceIgnoreDifferences configures how the ApplicationSet controller will ignore differences in live +// applications when applying changes from generated applications. +message ApplicationSetResourceIgnoreDifferences { + // Name is the name of the application to ignore differences for. If not specified, the rule applies to all applications. + optional string name = 1; + + // JSONPointers is a list of JSON pointers to fields to ignore differences for. + repeated string jsonPointers = 2; + + // JQPathExpressions is a list of JQ path expressions to fields to ignore differences for. + repeated string jqPathExpressions = 3; } message ApplicationSetRolloutStep { @@ -281,6 +310,17 @@ message ApplicationSetSpec { optional ApplicationSetSyncPolicy syncPolicy = 4; optional ApplicationSetStrategy strategy = 5; + + optional ApplicationPreservedFields preservedFields = 6; + + repeated string goTemplateOptions = 7; + + // ApplyNestedSelectors enables selectors defined within the generators of two level-nested matrix or merge generators + optional bool applyNestedSelectors = 8; + + repeated ApplicationSetResourceIgnoreDifferences ignoreApplicationDifferences = 9; + + optional string templatePatch = 10; } // ApplicationSetStatus defines the observed state of ApplicationSet @@ -304,6 +344,11 @@ message ApplicationSetStrategy { message ApplicationSetSyncPolicy { // PreserveResourcesOnDeletion will preserve resources on deletion. If PreserveResourcesOnDeletion is set to true, these Applications will not be deleted. optional bool preserveResourcesOnDeletion = 1; + + // ApplicationsSync represents the policy applied on the generated applications. Possible values are create-only, create-update, create-delete, sync + // +kubebuilder:validation:Optional + // +kubebuilder:validation:Enum=create-only;create-update;create-delete;sync + optional string applicationsSync = 2; } // ApplicationSetTemplate represents argocd ApplicationSpec @@ -343,6 +388,11 @@ message ApplicationSetTerminalGenerator { optional DuckTypeGenerator clusterDecisionResource = 5; optional PullRequestGenerator pullRequest = 6; + + optional PluginGenerator plugin = 7; + + // Selector allows to post-filter all generator. + optional k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 8; } // ApplicationSource contains all required information about the source of an application @@ -403,7 +453,8 @@ message ApplicationSourceHelm { // ReleaseName is the Helm release name to use. If omitted it will use the application name optional string releaseName = 3; - // Values specifies Helm values to be passed to helm template, typically defined as a block + // Values specifies Helm values to be passed to helm template, typically defined as a block. ValuesObject takes precedence over Values, so use one or the other. + // +patchStrategy=replace optional string values = 4; // FileParameters are file parameters to the helm template @@ -420,6 +471,10 @@ message ApplicationSourceHelm { // SkipCrds skips custom resource definition installation step (Helm's --skip-crds) optional bool skipCrds = 9; + + // ValuesObject specifies Helm values to be passed to helm template, defined as a map. This takes precedence over Values. + // +kubebuilder:pruning:PreserveUnknownFields + optional k8s.io.apimachinery.pkg.runtime.RawExtension valuesObject = 10; } // ApplicationSourceJsonnet holds options specific to applications of type Jsonnet @@ -459,6 +514,24 @@ message ApplicationSourceKustomize { // ForceCommonAnnotations specifies whether to force applying common annotations to resources for Kustomize apps optional bool forceCommonAnnotations = 8; + + // Namespace sets the namespace that Kustomize adds to all resources + optional string namespace = 9; + + // CommonAnnotationsEnvsubst specifies whether to apply env variables substitution for annotation values + optional bool commonAnnotationsEnvsubst = 10; + + // Replicas is a list of Kustomize Replicas override specifications + repeated KustomizeReplica replicas = 11; + + // 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; + + // LabelWithoutSelector specifies whether to apply common labels to resource selectors or not + optional bool labelWithoutSelector = 14; } // ApplicationSourcePlugin holds options specific to config management plugins @@ -478,10 +551,10 @@ message ApplicationSourcePluginParameter { optional string string = 5; // Map is the value of a map type parameter. - map map = 3; + optional OptionalMap map = 3; // Array is the value of an array type parameter. - repeated string array = 4; + optional OptionalArray array = 4; } // ApplicationSpec represents desired application state. Contains link to repository with application definition and additional parameters link definition revision. @@ -554,6 +627,9 @@ message ApplicationStatus { // SourceTypes specifies the type of the sources included in the application repeated string sourceTypes = 12; + + // ControllerNamespace indicates the namespace in which the application controller is located + optional string controllerNamespace = 13; } // ApplicationSummary contains information about URLs and container images used by an application @@ -611,6 +687,23 @@ message BasicAuthBitbucketServer { optional SecretRef passwordRef = 2; } +// BearerTokenBitbucketCloud defines the Bearer token for BitBucket AppToken auth. +message BearerTokenBitbucketCloud { + // Password (or personal access token) reference. + optional SecretRef tokenRef = 1; +} + +// ChartDetails contains helm chart metadata for a specific version +message ChartDetails { + optional string description = 1; + + // The URL of this projects home page, e.g. "http://example.com" + optional string home = 2; + + // List of maintainer details, name and email, e.g. ["John Doe "] + repeated string maintainers = 3; +} + // Cluster is the definition of a cluster resource message Cluster { // Server is the API server URL of the Kubernetes cluster @@ -745,6 +838,9 @@ message ComparedTo { // Sources is a reference to the application's multiple sources used for comparison repeated ApplicationSource sources = 3; + + // IgnoreDifferences is a reference to the application's ignored differences used for comparison + repeated ResourceIgnoreDifferences ignoreDifferences = 4; } // ComponentParameter contains information about component parameter value @@ -851,6 +947,9 @@ message GitGenerator { optional ApplicationSetTemplate template = 6; optional string pathParamPrefix = 7; + + // Values contains key/value pairs which are passed directly as parameters to the template + map values = 8; } // GnuPGPublicKey is a representation of a GnuPG public key @@ -985,6 +1084,14 @@ message KnownTypeField { optional string type = 2; } +message KustomizeGvk { + optional string group = 1; + + optional string version = 2; + + optional string kind = 3; +} + // KustomizeOptions are options for kustomize to use when building manifests message KustomizeOptions { // BuildOptions is a string of build parameters to use when calling `kustomize build` @@ -994,11 +1101,48 @@ message KustomizeOptions { optional string binaryPath = 2; } +message KustomizePatch { + optional string path = 1; + + optional string patch = 2; + + optional KustomizeSelector target = 3; + + map options = 4; +} + +message KustomizeReplica { + // Name of Deployment or StatefulSet + optional string name = 1; + + // Number of replicas + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString count = 2; +} + +message KustomizeResId { + optional KustomizeGvk gvk = 1; + + optional string name = 2; + + optional string namespace = 3; +} + +message KustomizeSelector { + optional KustomizeResId resId = 1; + + optional string annotationSelector = 2; + + optional string labelSelector = 3; +} + // ListGenerator include items info message ListGenerator { + // +kubebuilder:validation:Optional repeated k8s.io.apiextensions_apiserver.pkg.apis.apiextensions.v1.JSON elements = 1; optional ApplicationSetTemplate template = 2; + + optional string elementsYaml = 3; } message ManagedNamespaceMetadata { @@ -1105,6 +1249,18 @@ message OperationState { optional int64 retryCount = 8; } +message OptionalArray { + // Array is the value of an array type parameter. + // +optional + repeated string array = 1; +} + +message OptionalMap { + // Map is the value of a map type parameter. + // +optional + map map = 1; +} + // OrphanedResourceKey is a reference to a resource to be ignored from message OrphanedResourceKey { optional string group = 1; @@ -1137,6 +1293,33 @@ message OverrideIgnoreDiff { repeated string managedFieldsManagers = 3; } +message PluginConfigMapRef { + // Name of the ConfigMap + optional string name = 1; +} + +// PluginGenerator defines connection info specific to Plugin. +message PluginGenerator { + optional PluginConfigMapRef configMapRef = 1; + + optional PluginInput input = 2; + + // RequeueAfterSeconds determines how long the ApplicationSet controller will wait before reconciling the ApplicationSet again. + optional int64 requeueAfterSeconds = 3; + + optional ApplicationSetTemplate template = 4; + + // Values contains key/value pairs which are passed directly as parameters to the template. These values will not be + // sent as parameters to the plugin. + map values = 5; +} + +message PluginInput { + // Parameters contains the information to pass to the plugin. It is a map. The keys must be strings, and the + // values can be any type. + map parameters = 1; +} + // ProjectRole represents a role that has access to a project message ProjectRole { // Name is a name for this role @@ -1173,9 +1356,53 @@ message PullRequestGenerator { optional int64 requeueAfterSeconds = 6; optional ApplicationSetTemplate template = 7; + + optional PullRequestGeneratorBitbucket bitbucket = 8; + + // Additional provider to use and config for it. + optional PullRequestGeneratorAzureDevOps azuredevops = 9; +} + +// PullRequestGeneratorAzureDevOps defines connection info specific to AzureDevOps. +message PullRequestGeneratorAzureDevOps { + // Azure DevOps org to scan. Required. + optional string organization = 1; + + // Azure DevOps project name to scan. Required. + optional string project = 2; + + // Azure DevOps repo name to scan. Required. + optional string repo = 3; + + // The Azure DevOps API URL to talk to. If blank, use https://dev.azure.com/. + optional string api = 4; + + // Authentication token reference. + optional SecretRef tokenRef = 5; + + // Labels is used to filter the PRs that you want to target + repeated string labels = 6; +} + +// PullRequestGeneratorBitbucket defines connection info specific to Bitbucket. +message PullRequestGeneratorBitbucket { + // Workspace to scan. Required. + optional string owner = 1; + + // Repo name to scan. Required. + optional string repo = 2; + + // The Bitbucket REST API URL to talk to. If blank, uses https://api.bitbucket.org/2.0. + optional string api = 3; + + // Credentials for Basic auth + optional BasicAuthBitbucketServer basicAuth = 4; + + // Credentials for AppToken (Bearer auth) + optional BearerTokenBitbucketCloud bearerToken = 5; } -// PullRequestGenerator defines connection info specific to BitbucketServer. +// PullRequestGeneratorBitbucketServer defines connection info specific to BitbucketServer. message PullRequestGeneratorBitbucketServer { // Project to scan. Required. optional string project = 1; @@ -1195,6 +1422,8 @@ message PullRequestGeneratorBitbucketServer { // pass for a pull request to be included. message PullRequestGeneratorFilter { optional string branchMatch = 1; + + optional string targetBranchMatch = 2; } // PullRequestGeneratorGitLab defines connection info specific to GitLab. @@ -1213,9 +1442,12 @@ message PullRequestGeneratorGitLab { // PullRequestState is an additional MRs filter to get only those with a certain state. Default: "" (all states) optional string pullRequestState = 5; + + // Skips validating the SCM provider's TLS certificate - useful for self-signed certificates.; default: false + optional bool insecure = 6; } -// PullRequestGenerator defines connection info specific to Gitea. +// PullRequestGeneratorGitea defines connection info specific to Gitea. message PullRequestGeneratorGitea { // Gitea org or user to scan. Required. optional string owner = 1; @@ -1305,6 +1537,9 @@ message RepoCreds { // Proxy specifies the HTTP/HTTPS proxy used to access repos at the repo server optional string proxy = 19; + + // ForceHttpBasicAuth specifies whether Argo CD should attempt to force basic auth for HTTP connections + optional bool forceHttpBasicAuth = 20; } // RepositoryList is a collection of Repositories. @@ -1379,6 +1614,9 @@ message Repository { // GCPServiceAccountKey specifies the service account key in JSON format to be used for getting credentials to Google Cloud Source repos optional string gcpServiceAccountKey = 21; + + // ForceHttpBasicAuth specifies whether Argo CD should attempt to force basic auth for HTTP connections + optional bool forceHttpBasicAuth = 22; } // A RepositoryCertificate is either SSH known hosts entry or TLS certificate @@ -1422,6 +1660,10 @@ message ResourceAction { repeated ResourceActionParam params = 2; optional bool disabled = 3; + + optional string iconClass = 4; + + optional string displayName = 5; } // TODO: describe this type @@ -1551,6 +1793,8 @@ message ResourceOverride { optional OverrideIgnoreDiff ignoreDifferences = 2; + optional OverrideIgnoreDiff ignoreResourceUpdates = 6; + repeated KnownTypeField knownTypeFields = 4; } @@ -1658,6 +1902,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 @@ -1707,6 +1954,28 @@ message SCMProviderGenerator { optional int64 requeueAfterSeconds = 9; optional ApplicationSetTemplate template = 10; + + // Values contains key/value pairs which are passed directly as parameters to the template + map values = 11; + + optional SCMProviderGeneratorAWSCodeCommit awsCodeCommit = 12; +} + +// SCMProviderGeneratorAWSCodeCommit defines connection info specific to AWS CodeCommit. +message SCMProviderGeneratorAWSCodeCommit { + // TagFilters provides the tag filter(s) for repo discovery + repeated TagFilter tagFilters = 1; + + // Role provides the AWS IAM role to assume, for cross-account repo discovery + // if not provided, AppSet controller will use its pod/node identity to discover. + optional string role = 2; + + // Region provides the AWS region to discover repos. + // if not provided, AppSet controller will infer the current region from environment. + optional string region = 3; + + // Scan all branches instead of just the default branch. + optional bool allBranches = 4; } // SCMProviderGeneratorAzureDevOps defines connection info specific to Azure DevOps. @@ -1829,6 +2098,15 @@ message SCMProviderGeneratorGitlab { // Scan all branches instead of just the default branch. optional bool allBranches = 5; + + // Skips validating the SCM provider's TLS certificate - useful for self-signed certificates.; default: false + optional bool insecure = 6; + + // When recursing through subgroups, also include shared Projects (true) or scan only the subgroups under same path (false). Defaults to "true" + optional bool includeSharedProjects = 7; + + // Filter repos list based on Gitlab Topic. + optional string topic = 8; } // Utility struct for a reference to a secret key. @@ -1908,6 +2186,9 @@ message SyncOperationResult { // Revisions holds the revision this sync operation was performed for respective indexed source in sources field repeated string revisions = 5; + + // ManagedNamespaceMetadata contains the current sync state of managed namespace metadata + optional ManagedNamespaceMetadata managedNamespaceMetadata = 6; } // SyncPolicy controls when a sync will be performed in response to updates in git @@ -1930,7 +2211,7 @@ message SyncPolicyAutomated { // Prune specifies whether to delete resources from the cluster that are not found in the sources anymore as part of automated sync (default: false) optional bool prune = 1; - // SelfHeal specifes whether to revert resources back to their desired state upon modification in the cluster (default: false) + // SelfHeal specifies whether to revert resources back to their desired state upon modification in the cluster (default: false) optional bool selfHeal = 2; // AllowEmpty allows apps have zero live resources (default: false) @@ -2027,3 +2308,9 @@ message TLSClientConfig { optional bytes caData = 5; } +message TagFilter { + optional string key = 1; + + optional string value = 2; +} + diff --git a/pkg/apis/application/v1alpha1/openapi_generated.go b/pkg/apis/application/v1alpha1/openapi_generated.go index 17fbea6cf9e11..32eb8a725f353 100644 --- a/pkg/apis/application/v1alpha1/openapi_generated.go +++ b/pkg/apis/application/v1alpha1/openapi_generated.go @@ -14,141 +14,159 @@ import ( func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { return map[string]common.OpenAPIDefinition{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.AWSAuthConfig": schema_pkg_apis_application_v1alpha1_AWSAuthConfig(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.AppProject": schema_pkg_apis_application_v1alpha1_AppProject(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.AppProjectList": schema_pkg_apis_application_v1alpha1_AppProjectList(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.AppProjectSpec": schema_pkg_apis_application_v1alpha1_AppProjectSpec(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.AppProjectStatus": schema_pkg_apis_application_v1alpha1_AppProjectStatus(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Application": schema_pkg_apis_application_v1alpha1_Application(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationCondition": schema_pkg_apis_application_v1alpha1_ApplicationCondition(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationDestination": schema_pkg_apis_application_v1alpha1_ApplicationDestination(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationList": schema_pkg_apis_application_v1alpha1_ApplicationList(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationMatchExpression": schema_pkg_apis_application_v1alpha1_ApplicationMatchExpression(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSet": schema_pkg_apis_application_v1alpha1_ApplicationSet(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetApplicationStatus": schema_pkg_apis_application_v1alpha1_ApplicationSetApplicationStatus(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetCondition": schema_pkg_apis_application_v1alpha1_ApplicationSetCondition(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetGenerator": schema_pkg_apis_application_v1alpha1_ApplicationSetGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetList": schema_pkg_apis_application_v1alpha1_ApplicationSetList(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetNestedGenerator": schema_pkg_apis_application_v1alpha1_ApplicationSetNestedGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetRolloutStep": schema_pkg_apis_application_v1alpha1_ApplicationSetRolloutStep(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetRolloutStrategy": schema_pkg_apis_application_v1alpha1_ApplicationSetRolloutStrategy(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetSpec": schema_pkg_apis_application_v1alpha1_ApplicationSetSpec(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetStatus": schema_pkg_apis_application_v1alpha1_ApplicationSetStatus(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetStrategy": schema_pkg_apis_application_v1alpha1_ApplicationSetStrategy(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetSyncPolicy": schema_pkg_apis_application_v1alpha1_ApplicationSetSyncPolicy(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate": schema_pkg_apis_application_v1alpha1_ApplicationSetTemplate(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplateMeta": schema_pkg_apis_application_v1alpha1_ApplicationSetTemplateMeta(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTerminalGenerator": schema_pkg_apis_application_v1alpha1_ApplicationSetTerminalGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSource": schema_pkg_apis_application_v1alpha1_ApplicationSource(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSourceDirectory": schema_pkg_apis_application_v1alpha1_ApplicationSourceDirectory(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSourceHelm": schema_pkg_apis_application_v1alpha1_ApplicationSourceHelm(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSourceJsonnet": schema_pkg_apis_application_v1alpha1_ApplicationSourceJsonnet(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSourceKustomize": schema_pkg_apis_application_v1alpha1_ApplicationSourceKustomize(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSourcePlugin": schema_pkg_apis_application_v1alpha1_ApplicationSourcePlugin(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSourcePluginParameter": schema_pkg_apis_application_v1alpha1_ApplicationSourcePluginParameter(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSpec": schema_pkg_apis_application_v1alpha1_ApplicationSpec(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationStatus": schema_pkg_apis_application_v1alpha1_ApplicationStatus(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSummary": schema_pkg_apis_application_v1alpha1_ApplicationSummary(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationTree": schema_pkg_apis_application_v1alpha1_ApplicationTree(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationWatchEvent": schema_pkg_apis_application_v1alpha1_ApplicationWatchEvent(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Backoff": schema_pkg_apis_application_v1alpha1_Backoff(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.BasicAuthBitbucketServer": schema_pkg_apis_application_v1alpha1_BasicAuthBitbucketServer(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Cluster": schema_pkg_apis_application_v1alpha1_Cluster(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterCacheInfo": schema_pkg_apis_application_v1alpha1_ClusterCacheInfo(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterConfig": schema_pkg_apis_application_v1alpha1_ClusterConfig(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterGenerator": schema_pkg_apis_application_v1alpha1_ClusterGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterInfo": schema_pkg_apis_application_v1alpha1_ClusterInfo(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterList": schema_pkg_apis_application_v1alpha1_ClusterList(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Command": schema_pkg_apis_application_v1alpha1_Command(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ComparedTo": schema_pkg_apis_application_v1alpha1_ComparedTo(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ComponentParameter": schema_pkg_apis_application_v1alpha1_ComponentParameter(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ConfigManagementPlugin": schema_pkg_apis_application_v1alpha1_ConfigManagementPlugin(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ConnectionState": schema_pkg_apis_application_v1alpha1_ConnectionState(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.DuckTypeGenerator": schema_pkg_apis_application_v1alpha1_DuckTypeGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.EnvEntry": schema_pkg_apis_application_v1alpha1_EnvEntry(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ExecProviderConfig": schema_pkg_apis_application_v1alpha1_ExecProviderConfig(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GitDirectoryGeneratorItem": schema_pkg_apis_application_v1alpha1_GitDirectoryGeneratorItem(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GitFileGeneratorItem": schema_pkg_apis_application_v1alpha1_GitFileGeneratorItem(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GitGenerator": schema_pkg_apis_application_v1alpha1_GitGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GnuPGPublicKey": schema_pkg_apis_application_v1alpha1_GnuPGPublicKey(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GnuPGPublicKeyList": schema_pkg_apis_application_v1alpha1_GnuPGPublicKeyList(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HealthStatus": schema_pkg_apis_application_v1alpha1_HealthStatus(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmFileParameter": schema_pkg_apis_application_v1alpha1_HelmFileParameter(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmOptions": schema_pkg_apis_application_v1alpha1_HelmOptions(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmParameter": schema_pkg_apis_application_v1alpha1_HelmParameter(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HostInfo": schema_pkg_apis_application_v1alpha1_HostInfo(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HostResourceInfo": schema_pkg_apis_application_v1alpha1_HostResourceInfo(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Info": schema_pkg_apis_application_v1alpha1_Info(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.InfoItem": schema_pkg_apis_application_v1alpha1_InfoItem(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.JWTToken": schema_pkg_apis_application_v1alpha1_JWTToken(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.JWTTokens": schema_pkg_apis_application_v1alpha1_JWTTokens(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.JsonnetVar": schema_pkg_apis_application_v1alpha1_JsonnetVar(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KnownTypeField": schema_pkg_apis_application_v1alpha1_KnownTypeField(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizeOptions": schema_pkg_apis_application_v1alpha1_KustomizeOptions(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ListGenerator": schema_pkg_apis_application_v1alpha1_ListGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ManagedNamespaceMetadata": schema_pkg_apis_application_v1alpha1_ManagedNamespaceMetadata(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.MatrixGenerator": schema_pkg_apis_application_v1alpha1_MatrixGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.MergeGenerator": schema_pkg_apis_application_v1alpha1_MergeGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.NestedMatrixGenerator": schema_pkg_apis_application_v1alpha1_NestedMatrixGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.NestedMergeGenerator": schema_pkg_apis_application_v1alpha1_NestedMergeGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Operation": schema_pkg_apis_application_v1alpha1_Operation(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OperationInitiator": schema_pkg_apis_application_v1alpha1_OperationInitiator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OperationState": schema_pkg_apis_application_v1alpha1_OperationState(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OrphanedResourceKey": schema_pkg_apis_application_v1alpha1_OrphanedResourceKey(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OrphanedResourcesMonitorSettings": schema_pkg_apis_application_v1alpha1_OrphanedResourcesMonitorSettings(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OverrideIgnoreDiff": schema_pkg_apis_application_v1alpha1_OverrideIgnoreDiff(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ProjectRole": schema_pkg_apis_application_v1alpha1_ProjectRole(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGenerator": schema_pkg_apis_application_v1alpha1_PullRequestGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorBitbucketServer": schema_pkg_apis_application_v1alpha1_PullRequestGeneratorBitbucketServer(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorFilter": schema_pkg_apis_application_v1alpha1_PullRequestGeneratorFilter(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGitLab": schema_pkg_apis_application_v1alpha1_PullRequestGeneratorGitLab(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGitea": schema_pkg_apis_application_v1alpha1_PullRequestGeneratorGitea(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGithub": schema_pkg_apis_application_v1alpha1_PullRequestGeneratorGithub(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RefTarget": schema_pkg_apis_application_v1alpha1_RefTarget(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RepoCreds": schema_pkg_apis_application_v1alpha1_RepoCreds(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RepoCredsList": schema_pkg_apis_application_v1alpha1_RepoCredsList(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Repository": schema_pkg_apis_application_v1alpha1_Repository(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RepositoryCertificate": schema_pkg_apis_application_v1alpha1_RepositoryCertificate(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RepositoryCertificateList": schema_pkg_apis_application_v1alpha1_RepositoryCertificateList(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RepositoryList": schema_pkg_apis_application_v1alpha1_RepositoryList(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceAction": schema_pkg_apis_application_v1alpha1_ResourceAction(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceActionDefinition": schema_pkg_apis_application_v1alpha1_ResourceActionDefinition(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceActionParam": schema_pkg_apis_application_v1alpha1_ResourceActionParam(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceActions": schema_pkg_apis_application_v1alpha1_ResourceActions(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceDiff": schema_pkg_apis_application_v1alpha1_ResourceDiff(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceIgnoreDifferences": schema_pkg_apis_application_v1alpha1_ResourceIgnoreDifferences(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceNetworkingInfo": schema_pkg_apis_application_v1alpha1_ResourceNetworkingInfo(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceNode": schema_pkg_apis_application_v1alpha1_ResourceNode(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceOverride": schema_pkg_apis_application_v1alpha1_ResourceOverride(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceRef": schema_pkg_apis_application_v1alpha1_ResourceRef(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceResult": schema_pkg_apis_application_v1alpha1_ResourceResult(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceStatus": schema_pkg_apis_application_v1alpha1_ResourceStatus(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RetryStrategy": schema_pkg_apis_application_v1alpha1_RetryStrategy(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RevisionHistory": schema_pkg_apis_application_v1alpha1_RevisionHistory(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RevisionMetadata": schema_pkg_apis_application_v1alpha1_RevisionMetadata(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGenerator": schema_pkg_apis_application_v1alpha1_SCMProviderGenerator(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorAzureDevOps": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorAzureDevOps(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorBitbucket": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorBitbucket(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorBitbucketServer": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorBitbucketServer(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorFilter": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorFilter(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorGitea": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorGitea(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorGithub": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorGithub(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorGitlab": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorGitlab(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SecretRef": schema_pkg_apis_application_v1alpha1_SecretRef(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SignatureKey": schema_pkg_apis_application_v1alpha1_SignatureKey(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncOperation": schema_pkg_apis_application_v1alpha1_SyncOperation(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncOperationResource": schema_pkg_apis_application_v1alpha1_SyncOperationResource(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncOperationResult": schema_pkg_apis_application_v1alpha1_SyncOperationResult(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncPolicy": schema_pkg_apis_application_v1alpha1_SyncPolicy(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncPolicyAutomated": schema_pkg_apis_application_v1alpha1_SyncPolicyAutomated(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncStatus": schema_pkg_apis_application_v1alpha1_SyncStatus(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncStrategy": schema_pkg_apis_application_v1alpha1_SyncStrategy(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncStrategyApply": schema_pkg_apis_application_v1alpha1_SyncStrategyApply(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncStrategyHook": schema_pkg_apis_application_v1alpha1_SyncStrategyHook(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncWindow": schema_pkg_apis_application_v1alpha1_SyncWindow(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.TLSClientConfig": schema_pkg_apis_application_v1alpha1_TLSClientConfig(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.objectMeta": schema_pkg_apis_application_v1alpha1_objectMeta(ref), - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.rawResourceOverride": schema_pkg_apis_application_v1alpha1_rawResourceOverride(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.AWSAuthConfig": schema_pkg_apis_application_v1alpha1_AWSAuthConfig(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.AppProject": schema_pkg_apis_application_v1alpha1_AppProject(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.AppProjectList": schema_pkg_apis_application_v1alpha1_AppProjectList(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.AppProjectSpec": schema_pkg_apis_application_v1alpha1_AppProjectSpec(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.AppProjectStatus": schema_pkg_apis_application_v1alpha1_AppProjectStatus(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Application": schema_pkg_apis_application_v1alpha1_Application(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationCondition": schema_pkg_apis_application_v1alpha1_ApplicationCondition(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationDestination": schema_pkg_apis_application_v1alpha1_ApplicationDestination(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationList": schema_pkg_apis_application_v1alpha1_ApplicationList(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationMatchExpression": schema_pkg_apis_application_v1alpha1_ApplicationMatchExpression(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationPreservedFields": schema_pkg_apis_application_v1alpha1_ApplicationPreservedFields(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSet": schema_pkg_apis_application_v1alpha1_ApplicationSet(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetApplicationStatus": schema_pkg_apis_application_v1alpha1_ApplicationSetApplicationStatus(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetCondition": schema_pkg_apis_application_v1alpha1_ApplicationSetCondition(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetGenerator": schema_pkg_apis_application_v1alpha1_ApplicationSetGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetList": schema_pkg_apis_application_v1alpha1_ApplicationSetList(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetNestedGenerator": schema_pkg_apis_application_v1alpha1_ApplicationSetNestedGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetResourceIgnoreDifferences": schema_pkg_apis_application_v1alpha1_ApplicationSetResourceIgnoreDifferences(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetRolloutStep": schema_pkg_apis_application_v1alpha1_ApplicationSetRolloutStep(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetRolloutStrategy": schema_pkg_apis_application_v1alpha1_ApplicationSetRolloutStrategy(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetSpec": schema_pkg_apis_application_v1alpha1_ApplicationSetSpec(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetStatus": schema_pkg_apis_application_v1alpha1_ApplicationSetStatus(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetStrategy": schema_pkg_apis_application_v1alpha1_ApplicationSetStrategy(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetSyncPolicy": schema_pkg_apis_application_v1alpha1_ApplicationSetSyncPolicy(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate": schema_pkg_apis_application_v1alpha1_ApplicationSetTemplate(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplateMeta": schema_pkg_apis_application_v1alpha1_ApplicationSetTemplateMeta(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTerminalGenerator": schema_pkg_apis_application_v1alpha1_ApplicationSetTerminalGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSource": schema_pkg_apis_application_v1alpha1_ApplicationSource(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSourceDirectory": schema_pkg_apis_application_v1alpha1_ApplicationSourceDirectory(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSourceHelm": schema_pkg_apis_application_v1alpha1_ApplicationSourceHelm(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSourceJsonnet": schema_pkg_apis_application_v1alpha1_ApplicationSourceJsonnet(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSourceKustomize": schema_pkg_apis_application_v1alpha1_ApplicationSourceKustomize(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSourcePlugin": schema_pkg_apis_application_v1alpha1_ApplicationSourcePlugin(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSourcePluginParameter": schema_pkg_apis_application_v1alpha1_ApplicationSourcePluginParameter(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSpec": schema_pkg_apis_application_v1alpha1_ApplicationSpec(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationStatus": schema_pkg_apis_application_v1alpha1_ApplicationStatus(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSummary": schema_pkg_apis_application_v1alpha1_ApplicationSummary(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationTree": schema_pkg_apis_application_v1alpha1_ApplicationTree(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationWatchEvent": schema_pkg_apis_application_v1alpha1_ApplicationWatchEvent(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Backoff": schema_pkg_apis_application_v1alpha1_Backoff(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.BasicAuthBitbucketServer": schema_pkg_apis_application_v1alpha1_BasicAuthBitbucketServer(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.BearerTokenBitbucketCloud": schema_pkg_apis_application_v1alpha1_BearerTokenBitbucketCloud(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ChartDetails": schema_pkg_apis_application_v1alpha1_ChartDetails(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Cluster": schema_pkg_apis_application_v1alpha1_Cluster(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterCacheInfo": schema_pkg_apis_application_v1alpha1_ClusterCacheInfo(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterConfig": schema_pkg_apis_application_v1alpha1_ClusterConfig(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterGenerator": schema_pkg_apis_application_v1alpha1_ClusterGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterInfo": schema_pkg_apis_application_v1alpha1_ClusterInfo(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterList": schema_pkg_apis_application_v1alpha1_ClusterList(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Command": schema_pkg_apis_application_v1alpha1_Command(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ComparedTo": schema_pkg_apis_application_v1alpha1_ComparedTo(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ComponentParameter": schema_pkg_apis_application_v1alpha1_ComponentParameter(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ConfigManagementPlugin": schema_pkg_apis_application_v1alpha1_ConfigManagementPlugin(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ConnectionState": schema_pkg_apis_application_v1alpha1_ConnectionState(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.DuckTypeGenerator": schema_pkg_apis_application_v1alpha1_DuckTypeGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.EnvEntry": schema_pkg_apis_application_v1alpha1_EnvEntry(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ExecProviderConfig": schema_pkg_apis_application_v1alpha1_ExecProviderConfig(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GitDirectoryGeneratorItem": schema_pkg_apis_application_v1alpha1_GitDirectoryGeneratorItem(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GitFileGeneratorItem": schema_pkg_apis_application_v1alpha1_GitFileGeneratorItem(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GitGenerator": schema_pkg_apis_application_v1alpha1_GitGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GnuPGPublicKey": schema_pkg_apis_application_v1alpha1_GnuPGPublicKey(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GnuPGPublicKeyList": schema_pkg_apis_application_v1alpha1_GnuPGPublicKeyList(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HealthStatus": schema_pkg_apis_application_v1alpha1_HealthStatus(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmFileParameter": schema_pkg_apis_application_v1alpha1_HelmFileParameter(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmOptions": schema_pkg_apis_application_v1alpha1_HelmOptions(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmParameter": schema_pkg_apis_application_v1alpha1_HelmParameter(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HostInfo": schema_pkg_apis_application_v1alpha1_HostInfo(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HostResourceInfo": schema_pkg_apis_application_v1alpha1_HostResourceInfo(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Info": schema_pkg_apis_application_v1alpha1_Info(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.InfoItem": schema_pkg_apis_application_v1alpha1_InfoItem(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.JWTToken": schema_pkg_apis_application_v1alpha1_JWTToken(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.JWTTokens": schema_pkg_apis_application_v1alpha1_JWTTokens(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.JsonnetVar": schema_pkg_apis_application_v1alpha1_JsonnetVar(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KnownTypeField": schema_pkg_apis_application_v1alpha1_KnownTypeField(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizeGvk": schema_pkg_apis_application_v1alpha1_KustomizeGvk(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizeOptions": schema_pkg_apis_application_v1alpha1_KustomizeOptions(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizePatch": schema_pkg_apis_application_v1alpha1_KustomizePatch(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizeReplica": schema_pkg_apis_application_v1alpha1_KustomizeReplica(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizeResId": schema_pkg_apis_application_v1alpha1_KustomizeResId(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizeSelector": schema_pkg_apis_application_v1alpha1_KustomizeSelector(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ListGenerator": schema_pkg_apis_application_v1alpha1_ListGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ManagedNamespaceMetadata": schema_pkg_apis_application_v1alpha1_ManagedNamespaceMetadata(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.MatrixGenerator": schema_pkg_apis_application_v1alpha1_MatrixGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.MergeGenerator": schema_pkg_apis_application_v1alpha1_MergeGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.NestedMatrixGenerator": schema_pkg_apis_application_v1alpha1_NestedMatrixGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.NestedMergeGenerator": schema_pkg_apis_application_v1alpha1_NestedMergeGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Operation": schema_pkg_apis_application_v1alpha1_Operation(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OperationInitiator": schema_pkg_apis_application_v1alpha1_OperationInitiator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OperationState": schema_pkg_apis_application_v1alpha1_OperationState(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OptionalArray": schema_pkg_apis_application_v1alpha1_OptionalArray(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OptionalMap": schema_pkg_apis_application_v1alpha1_OptionalMap(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OrphanedResourceKey": schema_pkg_apis_application_v1alpha1_OrphanedResourceKey(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OrphanedResourcesMonitorSettings": schema_pkg_apis_application_v1alpha1_OrphanedResourcesMonitorSettings(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OverrideIgnoreDiff": schema_pkg_apis_application_v1alpha1_OverrideIgnoreDiff(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginConfigMapRef": schema_pkg_apis_application_v1alpha1_PluginConfigMapRef(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginGenerator": schema_pkg_apis_application_v1alpha1_PluginGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginInput": schema_pkg_apis_application_v1alpha1_PluginInput(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ProjectRole": schema_pkg_apis_application_v1alpha1_ProjectRole(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGenerator": schema_pkg_apis_application_v1alpha1_PullRequestGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorAzureDevOps": schema_pkg_apis_application_v1alpha1_PullRequestGeneratorAzureDevOps(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorBitbucket": schema_pkg_apis_application_v1alpha1_PullRequestGeneratorBitbucket(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorBitbucketServer": schema_pkg_apis_application_v1alpha1_PullRequestGeneratorBitbucketServer(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorFilter": schema_pkg_apis_application_v1alpha1_PullRequestGeneratorFilter(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGitLab": schema_pkg_apis_application_v1alpha1_PullRequestGeneratorGitLab(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGitea": schema_pkg_apis_application_v1alpha1_PullRequestGeneratorGitea(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGithub": schema_pkg_apis_application_v1alpha1_PullRequestGeneratorGithub(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RefTarget": schema_pkg_apis_application_v1alpha1_RefTarget(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RepoCreds": schema_pkg_apis_application_v1alpha1_RepoCreds(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RepoCredsList": schema_pkg_apis_application_v1alpha1_RepoCredsList(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.Repository": schema_pkg_apis_application_v1alpha1_Repository(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RepositoryCertificate": schema_pkg_apis_application_v1alpha1_RepositoryCertificate(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RepositoryCertificateList": schema_pkg_apis_application_v1alpha1_RepositoryCertificateList(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RepositoryList": schema_pkg_apis_application_v1alpha1_RepositoryList(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceAction": schema_pkg_apis_application_v1alpha1_ResourceAction(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceActionDefinition": schema_pkg_apis_application_v1alpha1_ResourceActionDefinition(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceActionParam": schema_pkg_apis_application_v1alpha1_ResourceActionParam(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceActions": schema_pkg_apis_application_v1alpha1_ResourceActions(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceDiff": schema_pkg_apis_application_v1alpha1_ResourceDiff(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceIgnoreDifferences": schema_pkg_apis_application_v1alpha1_ResourceIgnoreDifferences(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceNetworkingInfo": schema_pkg_apis_application_v1alpha1_ResourceNetworkingInfo(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceNode": schema_pkg_apis_application_v1alpha1_ResourceNode(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceOverride": schema_pkg_apis_application_v1alpha1_ResourceOverride(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceRef": schema_pkg_apis_application_v1alpha1_ResourceRef(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceResult": schema_pkg_apis_application_v1alpha1_ResourceResult(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceStatus": schema_pkg_apis_application_v1alpha1_ResourceStatus(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RetryStrategy": schema_pkg_apis_application_v1alpha1_RetryStrategy(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RevisionHistory": schema_pkg_apis_application_v1alpha1_RevisionHistory(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.RevisionMetadata": schema_pkg_apis_application_v1alpha1_RevisionMetadata(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGenerator": schema_pkg_apis_application_v1alpha1_SCMProviderGenerator(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorAWSCodeCommit": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorAWSCodeCommit(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorAzureDevOps": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorAzureDevOps(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorBitbucket": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorBitbucket(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorBitbucketServer": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorBitbucketServer(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorFilter": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorFilter(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorGitea": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorGitea(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorGithub": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorGithub(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorGitlab": schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorGitlab(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SecretRef": schema_pkg_apis_application_v1alpha1_SecretRef(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SignatureKey": schema_pkg_apis_application_v1alpha1_SignatureKey(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncOperation": schema_pkg_apis_application_v1alpha1_SyncOperation(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncOperationResource": schema_pkg_apis_application_v1alpha1_SyncOperationResource(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncOperationResult": schema_pkg_apis_application_v1alpha1_SyncOperationResult(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncPolicy": schema_pkg_apis_application_v1alpha1_SyncPolicy(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncPolicyAutomated": schema_pkg_apis_application_v1alpha1_SyncPolicyAutomated(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncStatus": schema_pkg_apis_application_v1alpha1_SyncStatus(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncStrategy": schema_pkg_apis_application_v1alpha1_SyncStrategy(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncStrategyApply": schema_pkg_apis_application_v1alpha1_SyncStrategyApply(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncStrategyHook": schema_pkg_apis_application_v1alpha1_SyncStrategyHook(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SyncWindow": schema_pkg_apis_application_v1alpha1_SyncWindow(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.TLSClientConfig": schema_pkg_apis_application_v1alpha1_TLSClientConfig(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.TagFilter": schema_pkg_apis_application_v1alpha1_TagFilter(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.objectMeta": schema_pkg_apis_application_v1alpha1_objectMeta(ref), + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.rawResourceOverride": schema_pkg_apis_application_v1alpha1_rawResourceOverride(ref), } } @@ -173,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: "", + }, + }, }, }, }, @@ -539,7 +564,7 @@ func schema_pkg_apis_application_v1alpha1_ApplicationCondition(ref common.Refere return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ApplicationCondition contains details about an application condition, which is usally an error or warning", + Description: "ApplicationCondition contains details about an application condition, which is usually an error or warning", Type: []string{"object"}, Properties: map[string]spec.Schema{ "type": { @@ -582,7 +607,7 @@ func schema_pkg_apis_application_v1alpha1_ApplicationDestination(ref common.Refe Properties: map[string]spec.Schema{ "server": { SchemaProps: spec.SchemaProps{ - Description: "Server specifies the URL of the target cluster and must be set to the Kubernetes control plane API", + Description: "Server specifies the URL of the target cluster's Kubernetes control plane API. This must be set if Name is not set.", Type: []string{"string"}, Format: "", }, @@ -596,7 +621,7 @@ func schema_pkg_apis_application_v1alpha1_ApplicationDestination(ref common.Refe }, "name": { SchemaProps: spec.SchemaProps{ - Description: "Name is an alternate way of specifying the target cluster by its symbolic name", + Description: "Name is an alternate way of specifying the target cluster by its symbolic name. This must be set if Server is not set.", Type: []string{"string"}, Format: "", }, @@ -694,6 +719,46 @@ func schema_pkg_apis_application_v1alpha1_ApplicationMatchExpression(ref common. } } +func schema_pkg_apis_application_v1alpha1_ApplicationPreservedFields(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "annotations": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "labels": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_application_v1alpha1_ApplicationSet(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -779,8 +844,16 @@ func schema_pkg_apis_application_v1alpha1_ApplicationSetApplicationStatus(ref co Format: "", }, }, + "step": { + SchemaProps: spec.SchemaProps{ + Description: "Step tracks which step this Application should be updated in", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, }, - Required: []string{"application", "message", "status"}, + Required: []string{"application", "message", "status", "step"}, }, }, Dependencies: []string{ @@ -895,11 +968,16 @@ func schema_pkg_apis_application_v1alpha1_ApplicationSetGenerator(ref common.Ref Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"), }, }, + "plugin": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginGenerator"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.DuckTypeGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GitGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ListGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.MatrixGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.MergeGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGenerator", "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"}, + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.DuckTypeGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GitGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ListGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.MatrixGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.MergeGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGenerator", "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"}, } } @@ -1007,11 +1085,66 @@ func schema_pkg_apis_application_v1alpha1_ApplicationSetNestedGenerator(ref comm Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"), }, }, + "plugin": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginGenerator"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.DuckTypeGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GitGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ListGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGenerator", "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON", "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"}, + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.DuckTypeGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GitGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ListGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGenerator", "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON", "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"}, + } +} + +func schema_pkg_apis_application_v1alpha1_ApplicationSetResourceIgnoreDifferences(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ApplicationSetResourceIgnoreDifferences configures how the ApplicationSet controller will ignore differences in live applications when applying changes from generated applications.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name is the name of the application to ignore differences for. If not specified, the rule applies to all applications.", + Type: []string{"string"}, + Format: "", + }, + }, + "jsonPointers": { + SchemaProps: spec.SchemaProps{ + Description: "JSONPointers is a list of JSON pointers to fields to ignore differences for.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "jqPathExpressions": { + SchemaProps: spec.SchemaProps{ + Description: "JQPathExpressions is a list of JQ path expressions to fields to ignore differences for.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, } } @@ -1116,12 +1249,57 @@ func schema_pkg_apis_application_v1alpha1_ApplicationSetSpec(ref common.Referenc Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetStrategy"), }, }, + "preservedFields": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationPreservedFields"), + }, + }, + "goTemplateOptions": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "applyNestedSelectors": { + SchemaProps: spec.SchemaProps{ + Description: "ApplyNestedSelectors enables selectors defined within the generators of two level-nested matrix or merge generators", + Type: []string{"boolean"}, + Format: "", + }, + }, + "ignoreApplicationDifferences": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetResourceIgnoreDifferences"), + }, + }, + }, + }, + }, + "templatePatch": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, }, Required: []string{"generators", "template"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetStrategy", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetSyncPolicy", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"}, + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationPreservedFields", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetResourceIgnoreDifferences", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetStrategy", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetSyncPolicy", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"}, } } @@ -1207,6 +1385,13 @@ func schema_pkg_apis_application_v1alpha1_ApplicationSetSyncPolicy(ref common.Re Format: "", }, }, + "applicationsSync": { + SchemaProps: spec.SchemaProps{ + Description: "ApplicationsSync represents the policy applied on the generated applications. Possible values are create-only, create-update, create-delete, sync", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -1347,11 +1532,22 @@ func schema_pkg_apis_application_v1alpha1_ApplicationSetTerminalGenerator(ref co Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGenerator"), }, }, + "plugin": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginGenerator"), + }, + }, + "selector": { + SchemaProps: spec.SchemaProps{ + Description: "Selector allows to post-filter all generator.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.DuckTypeGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GitGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ListGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGenerator"}, + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ClusterGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.DuckTypeGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.GitGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ListGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGenerator", "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"}, } } @@ -1518,8 +1714,13 @@ func schema_pkg_apis_application_v1alpha1_ApplicationSourceHelm(ref common.Refer }, }, "values": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-patch-strategy": "replace", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "Values specifies Helm values to be passed to helm template, typically defined as a block", + Description: "Values specifies Helm values to be passed to helm template, typically defined as a block. ValuesObject takes precedence over Values, so use one or the other.", Type: []string{"string"}, Format: "", }, @@ -1566,11 +1767,17 @@ func schema_pkg_apis_application_v1alpha1_ApplicationSourceHelm(ref common.Refer Format: "", }, }, + "valuesObject": { + SchemaProps: spec.SchemaProps{ + Description: "ValuesObject specifies Helm values to be passed to helm template, defined as a map. This takes precedence over Values.", + Ref: ref("k8s.io/apimachinery/pkg/runtime.RawExtension"), + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmFileParameter", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmParameter"}, + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmFileParameter", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.HelmParameter", "k8s.io/apimachinery/pkg/runtime.RawExtension"}, } } @@ -1721,9 +1928,75 @@ func schema_pkg_apis_application_v1alpha1_ApplicationSourceKustomize(ref common. Format: "", }, }, + "namespace": { + SchemaProps: spec.SchemaProps{ + Description: "Namespace sets the namespace that Kustomize adds to all resources", + Type: []string{"string"}, + Format: "", + }, + }, + "commonAnnotationsEnvsubst": { + SchemaProps: spec.SchemaProps{ + Description: "CommonAnnotationsEnvsubst specifies whether to apply env variables substitution for annotation values", + Type: []string{"boolean"}, + Format: "", + }, + }, + "replicas": { + SchemaProps: spec.SchemaProps{ + Description: "Replicas is a list of Kustomize Replicas override specifications", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizeReplica"), + }, + }, + }, + }, + }, + "patches": { + SchemaProps: spec.SchemaProps{ + Description: "Patches is a list of Kustomize patches", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizePatch"), + }, + }, + }, + }, + }, + "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: "", + }, + }, + }, + }, + }, + "labelWithoutSelector": { + SchemaProps: spec.SchemaProps{ + Description: "LabelWithoutSelector specifies whether to apply common labels to resource selectors or not", + Type: []string{"boolean"}, + Format: "", + }, + }, }, }, }, + Dependencies: []string{ + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizePatch", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizeReplica"}, } } @@ -1793,37 +2066,6 @@ func schema_pkg_apis_application_v1alpha1_ApplicationSourcePluginParameter(ref c Format: "", }, }, - "map": { - SchemaProps: spec.SchemaProps{ - Description: "Map is the value of a map type parameter.", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, - "array": { - SchemaProps: spec.SchemaProps{ - Description: "Array is the value of an array type parameter.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, - }, - }, }, }, }, @@ -2039,6 +2281,13 @@ func schema_pkg_apis_application_v1alpha1_ApplicationStatus(ref common.Reference }, }, }, + "controllerNamespace": { + SchemaProps: spec.SchemaProps{ + Description: "ControllerNamespace indicates the namespace in which the application controller is located", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -2241,19 +2490,82 @@ func schema_pkg_apis_application_v1alpha1_BasicAuthBitbucketServer(ref common.Re } } -func schema_pkg_apis_application_v1alpha1_Cluster(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_pkg_apis_application_v1alpha1_BearerTokenBitbucketCloud(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "Cluster is the definition of a cluster resource", + Description: "BearerTokenBitbucketCloud defines the Bearer token for BitBucket AppToken auth.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "server": { + "tokenRef": { SchemaProps: spec.SchemaProps{ - Description: "Server is the API server URL of the Kubernetes cluster", - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Password (or personal access token) reference.", + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SecretRef"), + }, + }, + }, + Required: []string{"tokenRef"}, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SecretRef"}, + } +} + +func schema_pkg_apis_application_v1alpha1_ChartDetails(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ChartDetails contains helm chart metadata for a specific version", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "description": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "home": { + SchemaProps: spec.SchemaProps{ + Description: "The URL of this projects home page, e.g. \"http://example.com\"", + Type: []string{"string"}, + Format: "", + }, + }, + "maintainers": { + SchemaProps: spec.SchemaProps{ + Description: "List of maintainer details, name and email, e.g. [\"John Doe \"]", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_application_v1alpha1_Cluster(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Cluster is the definition of a cluster resource", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "server": { + SchemaProps: spec.SchemaProps{ + Description: "Server is the API server URL of the Kubernetes cluster", + Default: "", + Type: []string{"string"}, + Format: "", }, }, "name": { @@ -2680,12 +2992,26 @@ func schema_pkg_apis_application_v1alpha1_ComparedTo(ref common.ReferenceCallbac }, }, }, + "ignoreDifferences": { + SchemaProps: spec.SchemaProps{ + Description: "IgnoreDifferences is a reference to the application's ignored differences used for comparison", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceIgnoreDifferences"), + }, + }, + }, + }, + }, }, Required: []string{"destination"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationDestination", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSource"}, + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationDestination", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSource", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceIgnoreDifferences"}, } } @@ -3070,6 +3396,22 @@ func schema_pkg_apis_application_v1alpha1_GitGenerator(ref common.ReferenceCallb Format: "", }, }, + "values": { + SchemaProps: spec.SchemaProps{ + Description: "Values contains key/value pairs which are passed directly as parameters to the template", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, }, Required: []string{"repoURL", "revision"}, }, @@ -3537,6 +3879,36 @@ func schema_pkg_apis_application_v1alpha1_KnownTypeField(ref common.ReferenceCal } } +func schema_pkg_apis_application_v1alpha1_KustomizeGvk(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "group": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "version": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_application_v1alpha1_KustomizeOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -3567,71 +3939,38 @@ func schema_pkg_apis_application_v1alpha1_KustomizeOptions(ref common.ReferenceC } } -func schema_pkg_apis_application_v1alpha1_ListGenerator(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_pkg_apis_application_v1alpha1_KustomizePatch(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ListGenerator include items info", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "elements": { + "path": { SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON"), - }, - }, - }, + Type: []string{"string"}, + Format: "", }, }, - "template": { + "patch": { SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"), + Type: []string{"string"}, + Format: "", }, }, - }, - Required: []string{"elements"}, - }, - }, - Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate", "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON"}, - } -} - -func schema_pkg_apis_application_v1alpha1_ManagedNamespaceMetadata(ref common.ReferenceCallback) common.OpenAPIDefinition { - return common.OpenAPIDefinition{ - Schema: spec.Schema{ - SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - Properties: map[string]spec.Schema{ - "labels": { + "target": { SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizeSelector"), }, }, - "annotations": { + "options": { SchemaProps: spec.SchemaProps{ Type: []string{"object"}, AdditionalProperties: &spec.SchemaOrBool{ Allows: true, Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, + Default: false, + Type: []string{"boolean"}, Format: "", }, }, @@ -3641,105 +3980,316 @@ func schema_pkg_apis_application_v1alpha1_ManagedNamespaceMetadata(ref common.Re }, }, }, + Dependencies: []string{ + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.KustomizeSelector"}, } } -func schema_pkg_apis_application_v1alpha1_MatrixGenerator(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_pkg_apis_application_v1alpha1_KustomizeReplica(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "MatrixGenerator generates the cartesian product of two sets of parameters. The parameters are defined by two nested generators.", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "generators": { + "name": { SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetNestedGenerator"), - }, - }, - }, + Description: "Name of Deployment or StatefulSet", + Default: "", + Type: []string{"string"}, + Format: "", }, }, - "template": { + "count": { SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"), + Description: "Number of replicas", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/util/intstr.IntOrString"), }, }, }, - Required: []string{"generators"}, + Required: []string{"name", "count"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetNestedGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"}, + "k8s.io/apimachinery/pkg/util/intstr.IntOrString"}, } } -func schema_pkg_apis_application_v1alpha1_MergeGenerator(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_pkg_apis_application_v1alpha1_KustomizeResId(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "MergeGenerator merges the output of two or more generators. Where the values for all specified merge keys are equal between two sets of generated parameters, the parameter sets will be merged with the parameters from the latter generator taking precedence. Parameter sets with merge keys not present in the base generator's params will be ignored. For example, if the first generator produced [{a: '1', b: '2'}, {c: '1', d: '1'}] and the second generator produced [{'a': 'override'}], the united parameters for merge keys = ['a'] would be [{a: 'override', b: '1'}, {c: '1', d: '1'}].\n\nMergeGenerator supports template overriding. If a MergeGenerator is one of multiple top-level generators, its template will be merged with the top-level generator before the parameters are applied.", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "generators": { + "group": { SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetNestedGenerator"), - }, - }, - }, + Type: []string{"string"}, + Format: "", }, }, - "mergeKeys": { + "version": { SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Type: []string{"string"}, + Format: "", }, }, - "template": { + "kind": { SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"), + Type: []string{"string"}, + Format: "", + }, + }, + "name": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "namespace": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", }, }, }, - Required: []string{"generators", "mergeKeys"}, }, }, - Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetNestedGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"}, } } -func schema_pkg_apis_application_v1alpha1_NestedMatrixGenerator(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_pkg_apis_application_v1alpha1_KustomizeSelector(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "NestedMatrixGenerator is a MatrixGenerator nested under another combination-type generator (MatrixGenerator or MergeGenerator). NestedMatrixGenerator does not have an override template, because template overriding has no meaning within the constituent generators of combination-type generators.\n\nNOTE: Nested matrix generator is not included directly in the CRD struct, instead it is included as a generic 'apiextensionsv1.JSON' object, and then marshalled into a NestedMatrixGenerator when processed.", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "generators": { + "group": { SchemaProps: spec.SchemaProps{ - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ + Type: []string{"string"}, + Format: "", + }, + }, + "version": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "name": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "namespace": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "annotationSelector": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "labelSelector": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_application_v1alpha1_ListGenerator(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ListGenerator include items info", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "elements": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON"), + }, + }, + }, + }, + }, + "template": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"), + }, + }, + "elementsYaml": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"elements"}, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate", "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON"}, + } +} + +func schema_pkg_apis_application_v1alpha1_ManagedNamespaceMetadata(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "labels": { + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "annotations": { + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_application_v1alpha1_MatrixGenerator(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MatrixGenerator generates the cartesian product of two sets of parameters. The parameters are defined by two nested generators.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "generators": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetNestedGenerator"), + }, + }, + }, + }, + }, + "template": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"), + }, + }, + }, + Required: []string{"generators"}, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetNestedGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"}, + } +} + +func schema_pkg_apis_application_v1alpha1_MergeGenerator(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MergeGenerator merges the output of two or more generators. Where the values for all specified merge keys are equal between two sets of generated parameters, the parameter sets will be merged with the parameters from the latter generator taking precedence. Parameter sets with merge keys not present in the base generator's params will be ignored. For example, if the first generator produced [{a: '1', b: '2'}, {c: '1', d: '1'}] and the second generator produced [{'a': 'override'}], the united parameters for merge keys = ['a'] would be [{a: 'override', b: '1'}, {c: '1', d: '1'}].\n\nMergeGenerator supports template overriding. If a MergeGenerator is one of multiple top-level generators, its template will be merged with the top-level generator before the parameters are applied.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "generators": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetNestedGenerator"), + }, + }, + }, + }, + }, + "mergeKeys": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "template": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"), + }, + }, + }, + Required: []string{"generators", "mergeKeys"}, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetNestedGenerator", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"}, + } +} + +func schema_pkg_apis_application_v1alpha1_NestedMatrixGenerator(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "NestedMatrixGenerator is a MatrixGenerator nested under another combination-type generator (MatrixGenerator or MergeGenerator). NestedMatrixGenerator does not have an override template, because template overriding has no meaning within the constituent generators of combination-type generators.\n\nNOTE: Nested matrix generator is not included directly in the CRD struct, instead it is included as a generic 'apiextensionsv1.JSON' object, and then marshalled into a NestedMatrixGenerator when processed.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "generators": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: map[string]interface{}{}, Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTerminalGenerator"), @@ -3939,29 +4489,25 @@ func schema_pkg_apis_application_v1alpha1_OperationState(ref common.ReferenceCal } } -func schema_pkg_apis_application_v1alpha1_OrphanedResourceKey(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_pkg_apis_application_v1alpha1_OptionalArray(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "OrphanedResourceKey is a reference to a resource to be ignored from", - Type: []string{"object"}, + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "group": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "kind": { - SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", - }, - }, - "name": { + "array": { SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", + Description: "Array is the value of an array type parameter.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, }, }, }, @@ -3970,11 +4516,70 @@ func schema_pkg_apis_application_v1alpha1_OrphanedResourceKey(ref common.Referen } } -func schema_pkg_apis_application_v1alpha1_OrphanedResourcesMonitorSettings(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_pkg_apis_application_v1alpha1_OptionalMap(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "OrphanedResourcesMonitorSettings holds settings of orphaned resources monitoring", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "map": { + SchemaProps: spec.SchemaProps{ + Description: "Map is the value of a map type parameter.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_application_v1alpha1_OrphanedResourceKey(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "OrphanedResourceKey is a reference to a resource to be ignored from", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "group": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "name": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_application_v1alpha1_OrphanedResourcesMonitorSettings(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "OrphanedResourcesMonitorSettings holds settings of orphaned resources monitoring", Type: []string{"object"}, Properties: map[string]spec.Schema{ "warn": { @@ -4065,60 +4670,309 @@ func schema_pkg_apis_application_v1alpha1_OverrideIgnoreDiff(ref common.Referenc } } -func schema_pkg_apis_application_v1alpha1_ProjectRole(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_pkg_apis_application_v1alpha1_PluginConfigMapRef(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name of the ConfigMap", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name"}, + }, + }, + } +} + +func schema_pkg_apis_application_v1alpha1_PluginGenerator(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PluginGenerator defines connection info specific to Plugin.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "configMapRef": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginConfigMapRef"), + }, + }, + "input": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginInput"), + }, + }, + "requeueAfterSeconds": { + SchemaProps: spec.SchemaProps{ + Description: "RequeueAfterSeconds determines how long the ApplicationSet controller will wait before reconciling the ApplicationSet again.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "template": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"), + }, + }, + "values": { + SchemaProps: spec.SchemaProps{ + Description: "Values contains key/value pairs which are passed directly as parameters to the template. These values will not be sent as parameters to the plugin.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + Required: []string{"configMapRef"}, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginConfigMapRef", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PluginInput"}, + } +} + +func schema_pkg_apis_application_v1alpha1_PluginInput(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "parameters": { + SchemaProps: spec.SchemaProps{ + Description: "Parameters contains the information to pass to the plugin. It is a map. The keys must be strings, and the values can be any type.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON"}, + } +} + +func schema_pkg_apis_application_v1alpha1_ProjectRole(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ProjectRole represents a role that has access to a project", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name is a name for this role", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "Description is a description of the role", + Type: []string{"string"}, + Format: "", + }, + }, + "policies": { + SchemaProps: spec.SchemaProps{ + Description: "Policies Stores a list of casbin formatted strings that define access policies for the role in the project", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "jwtTokens": { + SchemaProps: spec.SchemaProps{ + Description: "JWTTokens are a list of generated JWT tokens bound to this role", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.JWTToken"), + }, + }, + }, + }, + }, + "groups": { + SchemaProps: spec.SchemaProps{ + Description: "Groups are a list of OIDC group claims bound to this role", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + Required: []string{"name"}, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.JWTToken"}, + } +} + +func schema_pkg_apis_application_v1alpha1_PullRequestGenerator(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PullRequestGenerator defines a generator that scrapes a PullRequest API to find candidate pull requests.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "github": { + SchemaProps: spec.SchemaProps{ + Description: "Which provider to use and config for it.", + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGithub"), + }, + }, + "gitlab": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGitLab"), + }, + }, + "gitea": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGitea"), + }, + }, + "bitbucketServer": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorBitbucketServer"), + }, + }, + "filters": { + SchemaProps: spec.SchemaProps{ + Description: "Filters for which pull requests should be considered.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorFilter"), + }, + }, + }, + }, + }, + "requeueAfterSeconds": { + SchemaProps: spec.SchemaProps{ + Description: "Standard parameters.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "template": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"), + }, + }, + "bitbucket": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorBitbucket"), + }, + }, + "azuredevops": { + SchemaProps: spec.SchemaProps{ + Description: "Additional provider to use and config for it.", + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorAzureDevOps"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorAzureDevOps", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorBitbucket", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorBitbucketServer", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorFilter", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGitLab", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGitea", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGithub"}, + } +} + +func schema_pkg_apis_application_v1alpha1_PullRequestGeneratorAzureDevOps(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "ProjectRole represents a role that has access to a project", + Description: "PullRequestGeneratorAzureDevOps defines connection info specific to AzureDevOps.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "name": { + "organization": { SchemaProps: spec.SchemaProps{ - Description: "Name is a name for this role", + Description: "Azure DevOps org to scan. Required.", Default: "", Type: []string{"string"}, Format: "", }, }, - "description": { + "project": { SchemaProps: spec.SchemaProps{ - Description: "Description is a description of the role", + Description: "Azure DevOps project name to scan. Required.", + Default: "", Type: []string{"string"}, Format: "", }, }, - "policies": { + "repo": { SchemaProps: spec.SchemaProps{ - Description: "Policies Stores a list of casbin formatted strings that define access policies for the role in the project", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", - }, - }, - }, + Description: "Azure DevOps repo name to scan. Required.", + Default: "", + Type: []string{"string"}, + Format: "", }, }, - "jwtTokens": { + "api": { SchemaProps: spec.SchemaProps{ - Description: "JWTTokens are a list of generated JWT tokens bound to this role", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.JWTToken"), - }, - }, - }, + Description: "The Azure DevOps API URL to talk to. If blank, use https://dev.azure.com/.", + Type: []string{"string"}, + Format: "", }, }, - "groups": { + "tokenRef": { SchemaProps: spec.SchemaProps{ - Description: "Groups are a list of OIDC group claims bound to this role", + Description: "Authentication token reference.", + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SecretRef"), + }, + }, + "labels": { + SchemaProps: spec.SchemaProps{ + Description: "Labels is used to filter the PRs that you want to target", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -4132,74 +4986,62 @@ func schema_pkg_apis_application_v1alpha1_ProjectRole(ref common.ReferenceCallba }, }, }, - Required: []string{"name"}, + Required: []string{"organization", "project", "repo"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.JWTToken"}, + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SecretRef"}, } } -func schema_pkg_apis_application_v1alpha1_PullRequestGenerator(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_pkg_apis_application_v1alpha1_PullRequestGeneratorBitbucket(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "PullRequestGenerator defines a generator that scrapes a PullRequest API to find candidate pull requests.", + Description: "PullRequestGeneratorBitbucket defines connection info specific to Bitbucket.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "github": { - SchemaProps: spec.SchemaProps{ - Description: "Which provider to use and config for it.", - Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGithub"), - }, - }, - "gitlab": { - SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGitLab"), - }, - }, - "gitea": { + "owner": { SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGitea"), + Description: "Workspace to scan. Required.", + Default: "", + Type: []string{"string"}, + Format: "", }, }, - "bitbucketServer": { + "repo": { SchemaProps: spec.SchemaProps{ - Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorBitbucketServer"), + Description: "Repo name to scan. Required.", + Default: "", + Type: []string{"string"}, + Format: "", }, }, - "filters": { + "api": { SchemaProps: spec.SchemaProps{ - Description: "Filters for which pull requests should be considered.", - Type: []string{"array"}, - Items: &spec.SchemaOrArray{ - Schema: &spec.Schema{ - SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorFilter"), - }, - }, - }, + Description: "The Bitbucket REST API URL to talk to. If blank, uses https://api.bitbucket.org/2.0.", + Type: []string{"string"}, + Format: "", }, }, - "requeueAfterSeconds": { + "basicAuth": { SchemaProps: spec.SchemaProps{ - Description: "Standard parameters.", - Type: []string{"integer"}, - Format: "int64", + Description: "Credentials for Basic auth", + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.BasicAuthBitbucketServer"), }, }, - "template": { + "bearerToken": { SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"), + Description: "Credentials for AppToken (Bearer auth)", + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.BearerTokenBitbucketCloud"), }, }, }, + Required: []string{"owner", "repo"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorBitbucketServer", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorFilter", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGitLab", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGitea", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.PullRequestGeneratorGithub"}, + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.BasicAuthBitbucketServer", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.BearerTokenBitbucketCloud"}, } } @@ -4207,7 +5049,7 @@ func schema_pkg_apis_application_v1alpha1_PullRequestGeneratorBitbucketServer(re return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "PullRequestGenerator defines connection info specific to BitbucketServer.", + Description: "PullRequestGeneratorBitbucketServer defines connection info specific to BitbucketServer.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "project": { @@ -4262,6 +5104,12 @@ func schema_pkg_apis_application_v1alpha1_PullRequestGeneratorFilter(ref common. Format: "", }, }, + "targetBranchMatch": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -4318,6 +5166,13 @@ func schema_pkg_apis_application_v1alpha1_PullRequestGeneratorGitLab(ref common. Format: "", }, }, + "insecure": { + SchemaProps: spec.SchemaProps{ + Description: "Skips validating the SCM provider's TLS certificate - useful for self-signed certificates.; default: false", + Type: []string{"boolean"}, + Format: "", + }, + }, }, Required: []string{"project"}, }, @@ -4331,7 +5186,7 @@ func schema_pkg_apis_application_v1alpha1_PullRequestGeneratorGitea(ref common.R return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "PullRequestGenerator defines connection info specific to Gitea.", + Description: "PullRequestGeneratorGitea defines connection info specific to Gitea.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "owner": { @@ -4588,6 +5443,13 @@ func schema_pkg_apis_application_v1alpha1_RepoCreds(ref common.ReferenceCallback Format: "", }, }, + "forceHttpBasicAuth": { + SchemaProps: spec.SchemaProps{ + Description: "ForceHttpBasicAuth specifies whether Argo CD should attempt to force basic auth for HTTP connections", + Type: []string{"boolean"}, + Format: "", + }, + }, }, Required: []string{"url"}, }, @@ -4785,6 +5647,13 @@ func schema_pkg_apis_application_v1alpha1_Repository(ref common.ReferenceCallbac Format: "", }, }, + "forceHttpBasicAuth": { + SchemaProps: spec.SchemaProps{ + Description: "ForceHttpBasicAuth specifies whether Argo CD should attempt to force basic auth for HTTP connections", + Type: []string{"boolean"}, + Format: "", + }, + }, }, Required: []string{"repo"}, }, @@ -4948,6 +5817,18 @@ func schema_pkg_apis_application_v1alpha1_ResourceAction(ref common.ReferenceCal Format: "", }, }, + "iconClass": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "displayName": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -5456,6 +6337,12 @@ func schema_pkg_apis_application_v1alpha1_ResourceOverride(ref common.ReferenceC Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OverrideIgnoreDiff"), }, }, + "IgnoreResourceUpdates": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OverrideIgnoreDiff"), + }, + }, "KnownTypeFields": { SchemaProps: spec.SchemaProps{ Type: []string{"array"}, @@ -5470,7 +6357,7 @@ func schema_pkg_apis_application_v1alpha1_ResourceOverride(ref common.ReferenceC }, }, }, - Required: []string{"HealthLua", "UseOpenLibs", "Actions", "IgnoreDifferences", "KnownTypeFields"}, + Required: []string{"HealthLua", "UseOpenLibs", "Actions", "IgnoreDifferences", "IgnoreResourceUpdates", "KnownTypeFields"}, }, }, Dependencies: []string{ @@ -5789,12 +6676,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"}, } } @@ -5929,11 +6823,81 @@ func schema_pkg_apis_application_v1alpha1_SCMProviderGenerator(ref common.Refere Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate"), }, }, + "values": { + SchemaProps: spec.SchemaProps{ + Description: "Values contains key/value pairs which are passed directly as parameters to the template", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "awsCodeCommit": { + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorAWSCodeCommit"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorAWSCodeCommit", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorAzureDevOps", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorBitbucket", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorBitbucketServer", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorFilter", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorGitea", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorGithub", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorGitlab"}, + } +} + +func schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorAWSCodeCommit(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "SCMProviderGeneratorAWSCodeCommit defines connection info specific to AWS CodeCommit.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "tagFilters": { + SchemaProps: spec.SchemaProps{ + Description: "TagFilters provides the tag filter(s) for repo discovery", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.TagFilter"), + }, + }, + }, + }, + }, + "role": { + SchemaProps: spec.SchemaProps{ + Description: "Role provides the AWS IAM role to assume, for cross-account repo discovery if not provided, AppSet controller will use its pod/node identity to discover.", + Type: []string{"string"}, + Format: "", + }, + }, + "region": { + SchemaProps: spec.SchemaProps{ + Description: "Region provides the AWS region to discover repos. if not provided, AppSet controller will infer the current region from environment.", + Type: []string{"string"}, + Format: "", + }, + }, + "allBranches": { + SchemaProps: spec.SchemaProps{ + Description: "Scan all branches instead of just the default branch.", + Type: []string{"boolean"}, + Format: "", + }, + }, }, }, }, Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSetTemplate", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorAzureDevOps", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorBitbucket", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorBitbucketServer", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorFilter", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorGitea", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorGithub", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.SCMProviderGeneratorGitlab"}, + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.TagFilter"}, } } @@ -6288,6 +7252,27 @@ func schema_pkg_apis_application_v1alpha1_SCMProviderGeneratorGitlab(ref common. Format: "", }, }, + "insecure": { + SchemaProps: spec.SchemaProps{ + Description: "Skips validating the SCM provider's TLS certificate - useful for self-signed certificates.; default: false", + Type: []string{"boolean"}, + Format: "", + }, + }, + "includeSharedProjects": { + SchemaProps: spec.SchemaProps{ + Description: "When recursing through subgroups, also include shared Projects (true) or scan only the subgroups under same path (false). Defaults to \"true\"", + Type: []string{"boolean"}, + Format: "", + }, + }, + "topic": { + SchemaProps: spec.SchemaProps{ + Description: "Filter repos list based on Gitlab Topic.", + Type: []string{"string"}, + Format: "", + }, + }, }, Required: []string{"group"}, }, @@ -6572,12 +7557,18 @@ func schema_pkg_apis_application_v1alpha1_SyncOperationResult(ref common.Referen }, }, }, + "managedNamespaceMetadata": { + SchemaProps: spec.SchemaProps{ + Description: "ManagedNamespaceMetadata contains the current sync state of managed namespace metadata", + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ManagedNamespaceMetadata"), + }, + }, }, Required: []string{"revision"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSource", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceResult"}, + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSource", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ManagedNamespaceMetadata", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ResourceResult"}, } } @@ -6645,7 +7636,7 @@ func schema_pkg_apis_application_v1alpha1_SyncPolicyAutomated(ref common.Referen }, "selfHeal": { SchemaProps: spec.SchemaProps{ - Description: "SelfHeal specifes whether to revert resources back to their desired state upon modification in the cluster (default: false)", + Description: "SelfHeal specifies whether to revert resources back to their desired state upon modification in the cluster (default: false)", Type: []string{"boolean"}, Format: "", }, @@ -6926,6 +7917,32 @@ func schema_pkg_apis_application_v1alpha1_TLSClientConfig(ref common.ReferenceCa } } +func schema_pkg_apis_application_v1alpha1_TagFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "key": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "value": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"key"}, + }, + }, + } +} + func schema_pkg_apis_application_v1alpha1_objectMeta(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -6976,6 +7993,12 @@ func schema_pkg_apis_application_v1alpha1_rawResourceOverride(ref common.Referen Format: "", }, }, + "ignoreResourceUpdates": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, "knownTypeFields": { SchemaProps: spec.SchemaProps{ Type: []string{"array"}, diff --git a/pkg/apis/application/v1alpha1/repository_types.go b/pkg/apis/application/v1alpha1/repository_types.go index 2104f2b141434..3a557813d87c6 100644 --- a/pkg/apis/application/v1alpha1/repository_types.go +++ b/pkg/apis/application/v1alpha1/repository_types.go @@ -1,6 +1,7 @@ package v1alpha1 import ( + "fmt" "net/url" "github.com/argoproj/argo-cd/v2/util/cert" @@ -41,6 +42,8 @@ type RepoCreds struct { GCPServiceAccountKey string `json:"gcpServiceAccountKey,omitempty" protobuf:"bytes,13,opt,name=gcpServiceAccountKey"` // Proxy specifies the HTTP/HTTPS proxy used to access repos at the repo server Proxy string `json:"proxy,omitempty" protobuf:"bytes,19,opt,name=proxy"` + // ForceHttpBasicAuth specifies whether Argo CD should attempt to force basic auth for HTTP connections + ForceHttpBasicAuth bool `json:"forceHttpBasicAuth,omitempty" protobuf:"bytes,20,opt,name=forceHttpBasicAuth"` } // Repository is a repository holding application configurations @@ -88,6 +91,8 @@ type Repository struct { Project string `json:"project,omitempty" protobuf:"bytes,20,opt,name=project"` // GCPServiceAccountKey specifies the service account key in JSON format to be used for getting credentials to Google Cloud Source repos GCPServiceAccountKey string `json:"gcpServiceAccountKey,omitempty" protobuf:"bytes,21,opt,name=gcpServiceAccountKey"` + // ForceHttpBasicAuth specifies whether Argo CD should attempt to force basic auth for HTTP connections + ForceHttpBasicAuth bool `json:"forceHttpBasicAuth,omitempty" protobuf:"bytes,22,opt,name=forceHttpBasicAuth"` } // IsInsecure returns true if the repository has been configured to skip server verification @@ -138,6 +143,7 @@ func (repo *Repository) CopyCredentialsFromRepo(source *Repository) { if repo.GCPServiceAccountKey == "" { repo.GCPServiceAccountKey = source.GCPServiceAccountKey } + repo.ForceHttpBasicAuth = source.ForceHttpBasicAuth } } @@ -177,6 +183,7 @@ func (repo *Repository) CopyCredentialsFrom(source *RepoCreds) { if repo.Proxy == "" { repo.Proxy = source.Proxy } + repo.ForceHttpBasicAuth = source.ForceHttpBasicAuth } } @@ -186,16 +193,16 @@ func (repo *Repository) GetGitCreds(store git.CredsStore) git.Creds { return git.NopCreds{} } if repo.Password != "" { - return git.NewHTTPSCreds(repo.Username, repo.Password, repo.TLSClientCertData, repo.TLSClientCertKey, repo.IsInsecure(), repo.Proxy, store) + 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) } if repo.GCPServiceAccountKey != "" { - return git.NewGoogleCloudCreds(repo.GCPServiceAccountKey) + return git.NewGoogleCloudCreds(repo.GCPServiceAccountKey, store) } return git.NopCreds{} } @@ -259,6 +266,14 @@ func (m *Repository) CopySettingsFrom(source *Repository) { } } +// StringForLogging gets a string representation of the Repository which is safe to log or return to the user. +func (m *Repository) StringForLogging() string { + if m == nil { + return "" + } + return fmt.Sprintf("&Repository{Repo: %q, Type: %q, Name: %q, Project: %q}", m.Repo, m.Type, m.Name, m.Project) +} + // Repositories defines a list of Repository configurations type Repositories []*Repository diff --git a/pkg/apis/application/v1alpha1/types.go b/pkg/apis/application/v1alpha1/types.go index 409489b14bb67..abd2735710e72 100644 --- a/pkg/apis/application/v1alpha1/types.go +++ b/pkg/apis/application/v1alpha1/types.go @@ -18,7 +18,6 @@ import ( "github.com/argoproj/gitops-engine/pkg/health" synccommon "github.com/argoproj/gitops-engine/pkg/sync/common" - "github.com/ghodss/yaml" "github.com/robfig/cron/v3" log "github.com/sirupsen/logrus" "google.golang.org/grpc/codes" @@ -26,16 +25,21 @@ import ( v1 "k8s.io/api/core/v1" 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/runtime/schema" + "k8s.io/apimachinery/pkg/util/intstr" utilnet "k8s.io/apimachinery/pkg/util/net" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd/api" + "sigs.k8s.io/yaml" "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" ) @@ -67,7 +71,7 @@ type ApplicationSpec struct { // SyncPolicy controls when and how a sync will be performed SyncPolicy *SyncPolicy `json:"syncPolicy,omitempty" protobuf:"bytes,4,name=syncPolicy"` // IgnoreDifferences is a list of resources and their fields which should be ignored during comparison - IgnoreDifferences []ResourceIgnoreDifferences `json:"ignoreDifferences,omitempty" protobuf:"bytes,5,name=ignoreDifferences"` + IgnoreDifferences IgnoreDifferences `json:"ignoreDifferences,omitempty" protobuf:"bytes,5,name=ignoreDifferences"` // Info contains a list of information (URLs, email addresses, and plain text) that relates to the application Info []Info `json:"info,omitempty" protobuf:"bytes,6,name=info"` // RevisionHistoryLimit limits the number of items kept in the application's revision history, which is used for informational purposes as well as for rollbacks to previous versions. @@ -81,6 +85,12 @@ type ApplicationSpec struct { Sources ApplicationSources `json:"sources,omitempty" protobuf:"bytes,8,opt,name=sources"` } +type IgnoreDifferences []ResourceIgnoreDifferences + +func (id IgnoreDifferences) Equals(other IgnoreDifferences) bool { + return reflect.DeepEqual(id, other) +} + type TrackingMethod string // ResourceIgnoreDifferences contains resource filter and list of json paths which should be ignored during comparison with live state. @@ -183,6 +193,18 @@ type ApplicationSource struct { // ApplicationSources contains list of required information about the sources of an application type ApplicationSources []ApplicationSource +func (s ApplicationSources) Equals(other ApplicationSources) bool { + if len(s) != len(other) { + return false + } + for i := range s { + if !s[i].Equals(&other[i]) { + return false + } + } + return true +} + func (a *ApplicationSpec) GetSource() ApplicationSource { // if Application has multiple sources, return the first source in sources if a.HasMultipleSources() { @@ -208,9 +230,12 @@ func (a *ApplicationSpec) HasMultipleSources() bool { return a.Sources != nil && len(a.Sources) > 0 } -func (a *ApplicationSpec) GetSourcePtr() *ApplicationSource { +func (a *ApplicationSpec) GetSourcePtr(index int) *ApplicationSource { // if Application has multiple sources, return the first source in sources if a.HasMultipleSources() { + if index > 0 { + return &a.Sources[index-1] + } return &a.Sources[0] } return a.Source @@ -285,8 +310,9 @@ type ApplicationSourceHelm struct { Parameters []HelmParameter `json:"parameters,omitempty" protobuf:"bytes,2,opt,name=parameters"` // ReleaseName is the Helm release name to use. If omitted it will use the application name ReleaseName string `json:"releaseName,omitempty" protobuf:"bytes,3,opt,name=releaseName"` - // Values specifies Helm values to be passed to helm template, typically defined as a block - Values string `json:"values,omitempty" protobuf:"bytes,4,opt,name=values"` + // Values specifies Helm values to be passed to helm template, typically defined as a block. ValuesObject takes precedence over Values, so use one or the other. + // +patchStrategy=replace + Values string `json:"values,omitempty" patchStrategy:"replace" protobuf:"bytes,4,opt,name=values"` // FileParameters are file parameters to the helm template FileParameters []HelmFileParameter `json:"fileParameters,omitempty" protobuf:"bytes,5,opt,name=fileParameters"` // Version is the Helm version to use for templating ("3") @@ -297,6 +323,9 @@ type ApplicationSourceHelm struct { IgnoreMissingValueFiles bool `json:"ignoreMissingValueFiles,omitempty" protobuf:"bytes,8,opt,name=ignoreMissingValueFiles"` // SkipCrds skips custom resource definition installation step (Helm's --skip-crds) SkipCrds bool `json:"skipCrds,omitempty" protobuf:"bytes,9,opt,name=skipCrds"` + // ValuesObject specifies Helm values to be passed to helm template, defined as a map. This takes precedence over Values. + // +kubebuilder:pruning:PreserveUnknownFields + ValuesObject *runtime.RawExtension `json:"valuesObject,omitempty" protobuf:"bytes,10,opt,name=valuesObject"` } // HelmParameter is a parameter that's passed to helm template during manifest generation @@ -378,7 +407,7 @@ func (in *ApplicationSourceHelm) AddFileParameter(p HelmFileParameter) { // IsZero Returns true if the Helm options in an application source are considered zero func (h *ApplicationSourceHelm) IsZero() bool { - return h == nil || (h.Version == "") && (h.ReleaseName == "") && len(h.ValueFiles) == 0 && len(h.Parameters) == 0 && len(h.FileParameters) == 0 && h.Values == "" && !h.PassCredentials && !h.IgnoreMissingValueFiles && !h.SkipCrds + return h == nil || (h.Version == "") && (h.ReleaseName == "") && len(h.ValueFiles) == 0 && len(h.Parameters) == 0 && len(h.FileParameters) == 0 && h.ValuesIsEmpty() && !h.PassCredentials && !h.IgnoreMissingValueFiles && !h.SkipCrds } // KustomizeImage represents a Kustomize image definition in the format [old_image_name=]: @@ -433,14 +462,109 @@ type ApplicationSourceKustomize struct { ForceCommonLabels bool `json:"forceCommonLabels,omitempty" protobuf:"bytes,7,opt,name=forceCommonLabels"` // ForceCommonAnnotations specifies whether to force applying common annotations to resources for Kustomize apps ForceCommonAnnotations bool `json:"forceCommonAnnotations,omitempty" protobuf:"bytes,8,opt,name=forceCommonAnnotations"` + // Namespace sets the namespace that Kustomize adds to all resources + Namespace string `json:"namespace,omitempty" protobuf:"bytes,9,opt,name=namespace"` + // CommonAnnotationsEnvsubst specifies whether to apply env variables substitution for annotation values + CommonAnnotationsEnvsubst bool `json:"commonAnnotationsEnvsubst,omitempty" protobuf:"bytes,10,opt,name=commonAnnotationsEnvsubst"` + // Replicas is a list of Kustomize Replicas override specifications + 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"` + //LabelWithoutSelector specifies whether to apply common labels to resource selectors or not + LabelWithoutSelector bool `json:"labelWithoutSelector,omitempty" protobuf:"bytes,14,opt,name=labelWithoutSelector"` +} + +type KustomizeReplica struct { + // Name of Deployment or StatefulSet + Name string `json:"name" protobuf:"bytes,1,name=name"` + // Number of replicas + Count intstr.IntOrString `json:"count" protobuf:"bytes,2,name=count"` +} + +type KustomizeReplicas []KustomizeReplica + +// GetIntCount returns Count converted to int. +// If parsing error occurs, returns 0 and error. +func (kr KustomizeReplica) GetIntCount() (int, error) { + if kr.Count.Type == intstr.String { + if count, err := strconv.Atoi(kr.Count.StrVal); err != nil { + return 0, fmt.Errorf("expected integer value for count. Received: %s", kr.Count.StrVal) + } else { + return count, nil + } + } else { + return kr.Count.IntValue(), nil + } +} + +// NewKustomizeReplica parses a string in format name=count into a KustomizeReplica object and returns it +func NewKustomizeReplica(text string) (*KustomizeReplica, error) { + parts := strings.SplitN(text, "=", 2) + if len(parts) != 2 { + return nil, fmt.Errorf("expected parameter of the form: name=count. Received: %s", text) + } + + kr := &KustomizeReplica{ + Name: parts[0], + Count: intstr.Parse(parts[1]), + } + + if _, err := kr.GetIntCount(); err != nil { + return nil, err + } + + return kr, nil +} + +type KustomizePatches []KustomizePatch + +type KustomizePatch struct { + Path string `json:"path,omitempty" yaml:"path,omitempty" protobuf:"bytes,1,opt,name=path"` + Patch string `json:"patch,omitempty" yaml:"patch,omitempty" protobuf:"bytes,2,opt,name=patch"` + Target *KustomizeSelector `json:"target,omitempty" yaml:"target,omitempty" protobuf:"bytes,3,opt,name=target"` + Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty" protobuf:"bytes,4,opt,name=options"` +} + +// Copied from: https://github.com/kubernetes-sigs/kustomize/blob/cd7ba1744eadb793ab7cd056a76ee8a5ca725db9/api/types/patch.go +func (p *KustomizePatch) Equals(o KustomizePatch) bool { + targetEqual := (p.Target == o.Target) || + (p.Target != nil && o.Target != nil && *p.Target == *o.Target) + return p.Path == o.Path && + p.Patch == o.Patch && + targetEqual && + reflect.DeepEqual(p.Options, o.Options) +} + +type KustomizeSelector struct { + KustomizeResId `json:",inline,omitempty" yaml:",inline,omitempty" protobuf:"bytes,1,opt,name=resId"` + AnnotationSelector string `json:"annotationSelector,omitempty" yaml:"annotationSelector,omitempty" protobuf:"bytes,2,opt,name=annotationSelector"` + LabelSelector string `json:"labelSelector,omitempty" yaml:"labelSelector,omitempty" protobuf:"bytes,3,opt,name=labelSelector"` +} + +type KustomizeResId struct { + KustomizeGvk `json:",inline,omitempty" yaml:",inline,omitempty" protobuf:"bytes,1,opt,name=gvk"` + Name string `json:"name,omitempty" yaml:"name,omitempty" protobuf:"bytes,2,opt,name=name"` + Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty" protobuf:"bytes,3,opt,name=namespace"` +} + +type KustomizeGvk struct { + Group string `json:"group,omitempty" yaml:"group,omitempty" protobuf:"bytes,1,opt,name=group"` + Version string `json:"version,omitempty" yaml:"version,omitempty" protobuf:"bytes,2,opt,name=version"` + Kind string `json:"kind,omitempty" yaml:"kind,omitempty" protobuf:"bytes,3,opt,name=kind"` } // AllowsConcurrentProcessing returns true if multiple processes can run Kustomize builds on the same source at the same time func (k *ApplicationSourceKustomize) AllowsConcurrentProcessing() bool { return len(k.Images) == 0 && len(k.CommonLabels) == 0 && + len(k.CommonAnnotations) == 0 && k.NamePrefix == "" && - k.NameSuffix == "" + k.Namespace == "" && + k.NameSuffix == "" && + len(k.Patches) == 0 && + len(k.Components) == 0 } // IsZero returns true when the Kustomize options are considered empty @@ -449,9 +573,13 @@ func (k *ApplicationSourceKustomize) IsZero() bool { k.NamePrefix == "" && k.NameSuffix == "" && k.Version == "" && + k.Namespace == "" && len(k.Images) == 0 && + len(k.Replicas) == 0 && len(k.CommonLabels) == 0 && - len(k.CommonAnnotations) == 0 + len(k.CommonAnnotations) == 0 && + len(k.Patches) == 0 && + len(k.Components) == 0 } // MergeImage merges a new Kustomize image identifier in to a list of images @@ -464,6 +592,26 @@ func (k *ApplicationSourceKustomize) MergeImage(image KustomizeImage) { } } +// MergeReplicas merges a new Kustomize replica identifier in to a list of replicas +func (k *ApplicationSourceKustomize) MergeReplica(replica KustomizeReplica) { + i := k.Replicas.FindByName(replica.Name) + if i >= 0 { + k.Replicas[i] = replica + } else { + k.Replicas = append(k.Replicas, replica) + } +} + +// Find returns a positive integer representing the index in the list of replicas +func (rs KustomizeReplicas) FindByName(name string) int { + for i, r := range rs { + if r.Name == name { + return i + } + } + return -1 +} + // JsonnetVar represents a variable to be passed to jsonnet during manifest generation type JsonnetVar struct { Name string `json:"name" protobuf:"bytes,1,opt,name=name"` @@ -513,19 +661,155 @@ func (d *ApplicationSourceDirectory) IsZero() bool { return d == nil || !d.Recurse && d.Jsonnet.IsZero() } +type OptionalMap struct { + // Map is the value of a map type parameter. + // +optional + Map map[string]string `json:"map" protobuf:"bytes,1,rep,name=map"` + // We need the explicit +optional so that kube-builder generates the CRD without marking this as required. +} + +// Equals returns true if the two OptionalMap objects are equal. We can't use reflect.DeepEqual because it will return +// false if one of the maps is nil and the other is an empty map. This is because the JSON unmarshaller will set the +// map to nil if it is empty, but the protobuf unmarshaller will set it to an empty map. +func (o *OptionalMap) Equals(other *OptionalMap) bool { + if o == nil && other == nil { + return true + } + if o == nil || other == nil { + return false + } + if len(o.Map) != len(other.Map) { + return false + } + if o.Map == nil && other.Map == nil { + return true + } + // The next two blocks are critical. Depending on whether the struct was populated from JSON or protobufs, the map + // field will be either nil or an empty map. They mean the same thing: the map is empty. + if o.Map == nil && len(other.Map) == 0 { + return true + } + if other.Map == nil && len(o.Map) == 0 { + return true + } + return reflect.DeepEqual(o.Map, other.Map) +} + +type OptionalArray struct { + // Array is the value of an array type parameter. + // +optional + Array []string `json:"array" protobuf:"bytes,1,rep,name=array"` + // We need the explicit +optional so that kube-builder generates the CRD without marking this as required. +} + +// Equals returns true if the two OptionalArray objects are equal. We can't use reflect.DeepEqual because it will return +// false if one of the arrays is nil and the other is an empty array. This is because the JSON unmarshaller will set the +// array to nil if it is empty, but the protobuf unmarshaller will set it to an empty array. +func (o *OptionalArray) Equals(other *OptionalArray) bool { + if o == nil && other == nil { + return true + } + if o == nil || other == nil { + return false + } + if len(o.Array) != len(other.Array) { + return false + } + if o.Array == nil && other.Array == nil { + return true + } + // The next two blocks are critical. Depending on whether the struct was populated from JSON or protobufs, the array + // field will be either nil or an empty array. They mean the same thing: the array is empty. + if o.Array == nil && len(other.Array) == 0 { + return true + } + if other.Array == nil && len(o.Array) == 0 { + return true + } + return reflect.DeepEqual(o.Array, other.Array) +} + type ApplicationSourcePluginParameter struct { + // We use pointers to structs because go-to-protobuf represents pointers to arrays/maps as repeated fields. + // These repeated fields have no way to represent "present but empty." So we would have no way to distinguish + // {name: parameters, array: []} from {name: parameter} + // By wrapping the array/map in a struct, we can use a pointer to the struct to represent "present but empty." + // Name is the name identifying a parameter. Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"` // String_ is the value of a string type parameter. String_ *string `json:"string,omitempty" protobuf:"bytes,5,opt,name=string"` // Map is the value of a map type parameter. - Map map[string]string `json:"map,omitempty" protobuf:"bytes,3,rep,name=map"` + *OptionalMap `json:",omitempty" protobuf:"bytes,3,rep,name=map"` // Array is the value of an array type parameter. - Array []string `json:"array,omitempty" protobuf:"bytes,4,rep,name=array"` + *OptionalArray `json:",omitempty" protobuf:"bytes,4,rep,name=array"` +} + +func (p ApplicationSourcePluginParameter) Equals(other ApplicationSourcePluginParameter) bool { + if p.Name != other.Name { + return false + } + if !reflect.DeepEqual(p.String_, other.String_) { + return false + } + return p.OptionalMap.Equals(other.OptionalMap) && p.OptionalArray.Equals(other.OptionalArray) +} + +// MarshalJSON is a custom JSON marshaller for ApplicationSourcePluginParameter. We need this custom marshaler because, +// when ApplicationSourcePluginParameter is unmarshaled, either from JSON or protobufs, the fields inside OptionalMap and +// OptionalArray are not set. The default JSON marshaler marshals these as "null." But really what we want to represent +// is an empty map or array. +// +// There are efforts to change things upstream, but nothing has been merged yet. See https://github.com/golang/go/issues/37711 +func (p ApplicationSourcePluginParameter) MarshalJSON() ([]byte, error) { + out := map[string]interface{}{} + out["name"] = p.Name + if p.String_ != nil { + out["string"] = p.String_ + } + if p.OptionalMap != nil { + if p.OptionalMap.Map == nil { + // Nil is not the same as a nil map. Nil means the field was not set, while a nil map means the field was set to an empty map. + // Either way, we want to marshal it as "{}". + out["map"] = map[string]string{} + } else { + out["map"] = p.OptionalMap.Map + } + } + if p.OptionalArray != nil { + if p.OptionalArray.Array == nil { + // Nil is not the same as a nil array. Nil means the field was not set, while a nil array means the field was set to an empty array. + // Either way, we want to marshal it as "[]". + out["array"] = []string{} + } else { + out["array"] = p.OptionalArray.Array + } + } + bytes, err := json.Marshal(out) + if err != nil { + return nil, err + } + return bytes, nil } type ApplicationSourcePluginParameters []ApplicationSourcePluginParameter +func (p ApplicationSourcePluginParameters) Equals(other ApplicationSourcePluginParameters) bool { + if len(p) != len(other) { + return false + } + for i := range p { + if !p[i].Equals(other[i]) { + return false + } + } + return true +} + +func (p ApplicationSourcePluginParameters) IsZero() bool { + return len(p) == 0 +} + // Environ builds a list of environment variables to represent parameters sent to a plugin from the Application // manifest. Parameters are represented as one large stringified JSON array (under `ARGOCD_APP_PARAMETERS`). They're // also represented as individual environment variables, each variable's key being an escaped version of the parameter's @@ -544,13 +828,13 @@ func (p ApplicationSourcePluginParameters) Environ() ([]string, error) { if param.String_ != nil { env = append(env, fmt.Sprintf("%s=%s", envBaseName, *param.String_)) } - if param.Map != nil { - for key, value := range param.Map { + if param.OptionalMap != nil { + for key, value := range param.OptionalMap.Map { env = append(env, fmt.Sprintf("%s_%s=%s", envBaseName, escaped(key), value)) } } - if param.Array != nil { - for i, value := range param.Array { + if param.OptionalArray != nil { + for i, value := range param.OptionalArray.Array { env = append(env, fmt.Sprintf("%s_%d=%s", envBaseName, i, value)) } } @@ -572,9 +856,28 @@ type ApplicationSourcePlugin struct { Parameters ApplicationSourcePluginParameters `json:"parameters,omitempty" protobuf:"bytes,3,opt,name=parameters"` } +func (c *ApplicationSourcePlugin) Equals(other *ApplicationSourcePlugin) bool { + if c == nil && other == nil { + return true + } + if c == nil || other == nil { + return false + } + if !c.Parameters.Equals(other.Parameters) { + return false + } + // DeepEqual works fine for fields besides Parameters. Since we already know that Parameters are equal, we can + // set them to nil and then do a DeepEqual. + leftCopy := c.DeepCopy() + rightCopy := other.DeepCopy() + leftCopy.Parameters = nil + rightCopy.Parameters = nil + return reflect.DeepEqual(leftCopy, rightCopy) +} + // IsZero returns true if the ApplicationSourcePlugin is considered empty func (c *ApplicationSourcePlugin) IsZero() bool { - return c == nil || c.Name == "" && c.Env.IsZero() + return c == nil || c.Name == "" && c.Env.IsZero() && c.Parameters.IsZero() } // AddEnvEntry merges an EnvEntry into a list of entries. If an entry with the same name already exists, @@ -607,12 +910,12 @@ func (c *ApplicationSourcePlugin) RemoveEnvEntry(key string) error { // ApplicationDestination holds information about the application's destination type ApplicationDestination struct { - // Server specifies the URL of the target cluster and must be set to the Kubernetes control plane API + // Server specifies the URL of the target cluster's Kubernetes control plane API. This must be set if Name is not set. Server string `json:"server,omitempty" protobuf:"bytes,1,opt,name=server"` // Namespace specifies the target namespace for the application's resources. // The namespace will only be set for namespace-scoped resources that have not set a value for .metadata.namespace Namespace string `json:"namespace,omitempty" protobuf:"bytes,2,opt,name=namespace"` - // Name is an alternate way of specifying the target cluster by its symbolic name + // Name is an alternate way of specifying the target cluster by its symbolic name. This must be set if Server is not set. Name string `json:"name,omitempty" protobuf:"bytes,3,opt,name=name"` // nolint:govet @@ -653,6 +956,37 @@ type ApplicationStatus struct { ResourceHealthSource ResourceHealthLocation `json:"resourceHealthSource,omitempty" protobuf:"bytes,11,opt,name=resourceHealthSource"` // SourceTypes specifies the type of the sources included in the application SourceTypes []ApplicationSourceType `json:"sourceTypes,omitempty" protobuf:"bytes,12,opt,name=sourceTypes"` + // ControllerNamespace indicates the namespace in which the application controller is located + 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 @@ -839,11 +1173,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 @@ -913,7 +1248,7 @@ type Backoff struct { type SyncPolicyAutomated struct { // Prune specifies whether to delete resources from the cluster that are not found in the sources anymore as part of automated sync (default: false) Prune bool `json:"prune,omitempty" protobuf:"bytes,1,opt,name=prune"` - // SelfHeal specifes whether to revert resources back to their desired state upon modification in the cluster (default: false) + // SelfHeal specifies whether to revert resources back to their desired state upon modification in the cluster (default: false) SelfHeal bool `json:"selfHeal,omitempty" protobuf:"bytes,2,opt,name=selfHeal"` // AllowEmpty allows apps have zero live resources (default: false) AllowEmpty bool `json:"allowEmpty,omitempty" protobuf:"bytes,3,opt,name=allowEmpty"` @@ -973,6 +1308,15 @@ type RevisionMetadata struct { SignatureInfo string `json:"signatureInfo,omitempty" protobuf:"bytes,5,opt,name=signatureInfo"` } +// ChartDetails contains helm chart metadata for a specific version +type ChartDetails struct { + Description string `json:"description,omitempty" protobuf:"bytes,1,opt,name=description"` + // The URL of this projects home page, e.g. "http://example.com" + Home string `json:"home,omitempty" protobuf:"bytes,2,opt,name=home"` + // List of maintainer details, name and email, e.g. ["John Doe "] + Maintainers []string `json:"maintainers,omitempty" protobuf:"bytes,3,opt,name=maintainers"` +} + // SyncOperationResult represent result of sync operation type SyncOperationResult struct { // Resources contains a list of sync result items for each individual resource in a sync operation @@ -985,6 +1329,8 @@ type SyncOperationResult struct { Sources ApplicationSources `json:"sources,omitempty" protobuf:"bytes,4,opt,name=sources"` // Revisions holds the revision this sync operation was performed for respective indexed source in sources field Revisions []string `json:"revisions,omitempty" protobuf:"bytes,5,opt,name=revisions"` + // ManagedNamespaceMetadata contains the current sync state of managed namespace metadata + ManagedNamespaceMetadata *ManagedNamespaceMetadata `json:"managedNamespaceMetadata,omitempty" protobuf:"bytes,6,opt,name=managedNamespaceMetadata"` } // ResourceResult holds the operation result details of a specific resource @@ -1060,6 +1406,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. @@ -1129,7 +1477,7 @@ const ( ApplicationConditionOrphanedResourceWarning = "OrphanedResourceWarning" ) -// ApplicationCondition contains details about an application condition, which is usally an error or warning +// ApplicationCondition contains details about an application condition, which is usually an error or warning type ApplicationCondition struct { // Type is an application condition type Type ApplicationConditionType `json:"type" protobuf:"bytes,1,opt,name=type"` @@ -1147,6 +1495,8 @@ type ComparedTo struct { Destination ApplicationDestination `json:"destination" protobuf:"bytes,2,opt,name=destination"` // Sources is a reference to the application's multiple sources used for comparison Sources ApplicationSources `json:"sources,omitempty" protobuf:"bytes,3,opt,name=sources"` + // IgnoreDifferences is a reference to the application's ignored differences used for comparison + IgnoreDifferences IgnoreDifferences `json:"ignoreDifferences,omitempty" protobuf:"bytes,4,opt,name=ignoreDifferences"` } // SyncStatus contains information about the currently observed live and desired states of an application @@ -1511,6 +1861,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 @@ -1584,9 +1937,9 @@ type KnownTypeField struct { // OverrideIgnoreDiff contains configurations about how fields should be ignored during diffs between // the desired state and live state type OverrideIgnoreDiff struct { - //JSONPointers is a JSON path list following the format defined in RFC4627 (https://datatracker.ietf.org/doc/html/rfc6902#section-3) + // JSONPointers is a JSON path list following the format defined in RFC4627 (https://datatracker.ietf.org/doc/html/rfc6902#section-3) JSONPointers []string `json:"jsonPointers" protobuf:"bytes,1,rep,name=jSONPointers"` - //JQPathExpressions is a JQ path list that will be evaludated during the diff process + // JQPathExpressions is a JQ path list that will be evaludated during the diff process JQPathExpressions []string `json:"jqPathExpressions" protobuf:"bytes,2,opt,name=jqPathExpressions"` // ManagedFieldsManagers is a list of trusted managers. Fields mutated by those managers will take precedence over the // desired state defined in the SCM and won't be displayed in diffs @@ -1594,21 +1947,23 @@ type OverrideIgnoreDiff struct { } type rawResourceOverride struct { - HealthLua string `json:"health.lua,omitempty"` - UseOpenLibs bool `json:"health.lua.useOpenLibs,omitempty"` - Actions string `json:"actions,omitempty"` - IgnoreDifferences string `json:"ignoreDifferences,omitempty"` - KnownTypeFields []KnownTypeField `json:"knownTypeFields,omitempty"` + HealthLua string `json:"health.lua,omitempty"` + UseOpenLibs bool `json:"health.lua.useOpenLibs,omitempty"` + Actions string `json:"actions,omitempty"` + IgnoreDifferences string `json:"ignoreDifferences,omitempty"` + IgnoreResourceUpdates string `json:"ignoreResourceUpdates,omitempty"` + KnownTypeFields []KnownTypeField `json:"knownTypeFields,omitempty"` } // ResourceOverride holds configuration to customize resource diffing and health assessment // TODO: describe the members of this type type ResourceOverride struct { - HealthLua string `protobuf:"bytes,1,opt,name=healthLua"` - UseOpenLibs bool `protobuf:"bytes,5,opt,name=useOpenLibs"` - Actions string `protobuf:"bytes,3,opt,name=actions"` - IgnoreDifferences OverrideIgnoreDiff `protobuf:"bytes,2,opt,name=ignoreDifferences"` - KnownTypeFields []KnownTypeField `protobuf:"bytes,4,opt,name=knownTypeFields"` + HealthLua string `protobuf:"bytes,1,opt,name=healthLua"` + UseOpenLibs bool `protobuf:"bytes,5,opt,name=useOpenLibs"` + Actions string `protobuf:"bytes,3,opt,name=actions"` + IgnoreDifferences OverrideIgnoreDiff `protobuf:"bytes,2,opt,name=ignoreDifferences"` + IgnoreResourceUpdates OverrideIgnoreDiff `protobuf:"bytes,6,opt,name=ignoreResourceUpdates"` + KnownTypeFields []KnownTypeField `protobuf:"bytes,4,opt,name=knownTypeFields"` } // TODO: describe this method @@ -1621,7 +1976,15 @@ func (s *ResourceOverride) UnmarshalJSON(data []byte) error { s.HealthLua = raw.HealthLua s.UseOpenLibs = raw.UseOpenLibs s.Actions = raw.Actions - return yaml.Unmarshal([]byte(raw.IgnoreDifferences), &s.IgnoreDifferences) + err := yaml.Unmarshal([]byte(raw.IgnoreDifferences), &s.IgnoreDifferences) + if err != nil { + return err + } + err = yaml.Unmarshal([]byte(raw.IgnoreResourceUpdates), &s.IgnoreResourceUpdates) + if err != nil { + return err + } + return nil } // TODO: describe this method @@ -1630,7 +1993,11 @@ func (s ResourceOverride) MarshalJSON() ([]byte, error) { if err != nil { return nil, err } - raw := &rawResourceOverride{s.HealthLua, s.UseOpenLibs, s.Actions, string(ignoreDifferencesData), s.KnownTypeFields} + ignoreResourceUpdatesData, err := yaml.Marshal(s.IgnoreResourceUpdates) + if err != nil { + return nil, err + } + raw := &rawResourceOverride{s.HealthLua, s.UseOpenLibs, s.Actions, string(ignoreDifferencesData), string(ignoreResourceUpdatesData), s.KnownTypeFields} return json.Marshal(raw) } @@ -1661,9 +2028,11 @@ type ResourceActionDefinition struct { // TODO: describe this type // TODO: describe members of this type type ResourceAction struct { - Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"` - Params []ResourceActionParam `json:"params,omitempty" protobuf:"bytes,2,rep,name=params"` - Disabled bool `json:"disabled,omitempty" protobuf:"varint,3,opt,name=disabled"` + Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"` + Params []ResourceActionParam `json:"params,omitempty" protobuf:"bytes,2,rep,name=params"` + Disabled bool `json:"disabled,omitempty" protobuf:"varint,3,opt,name=disabled"` + IconClass string `json:"iconClass,omitempty" protobuf:"bytes,4,opt,name=iconClass"` + DisplayName string `json:"displayName,omitempty" protobuf:"bytes,5,opt,name=displayName"` } // TODO: describe this type @@ -1860,7 +2229,7 @@ type SyncWindow struct { Clusters []string `json:"clusters,omitempty" protobuf:"bytes,6,opt,name=clusters"` // ManualSync enables manual syncs when they would otherwise be blocked ManualSync bool `json:"manualSync,omitempty" protobuf:"bytes,7,opt,name=manualSync"` - //TimeZone of the sync that will be applied to the schedule + // TimeZone of the sync that will be applied to the schedule TimeZone string `json:"timeZone,omitempty" protobuf:"bytes,8,opt,name=timeZone"` } @@ -2056,6 +2425,10 @@ func (w *SyncWindows) CanSync(isManual bool) bool { } } + if active.hasAllow() { + return true + } + inactiveAllows := w.InactiveAllows() if inactiveAllows.HasWindows() { if isManual && inactiveAllows.manualEnabled() { @@ -2288,6 +2661,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) @@ -2330,6 +2715,13 @@ func (app *Application) GetPropagationPolicy() string { return "" } +// HasChangedManagedNamespaceMetadata checks whether app.Spec.SyncPolicy.ManagedNamespaceMetadata differs from the +// managed namespace metadata which has been stored app.Status.OperationState.SyncResult. If they differ a refresh should +// be triggered. +func (app *Application) HasChangedManagedNamespaceMetadata() bool { + return app.Spec.SyncPolicy != nil && app.Spec.SyncPolicy.ManagedNamespaceMetadata != nil && app.Status.OperationState != nil && app.Status.OperationState.SyncResult != nil && !reflect.DeepEqual(app.Spec.SyncPolicy.ManagedNamespaceMetadata, app.Status.OperationState.SyncResult.ManagedNamespaceMetadata) +} + // IsFinalizerPresent checks if the app has a given finalizer func (app *Application) IsFinalizerPresent(finalizer string) bool { return getFinalizerIndex(app.ObjectMeta, finalizer) > -1 @@ -2401,8 +2793,23 @@ func (condition *ApplicationCondition) IsError() bool { } // Equals compares two instances of ApplicationSource and return true if instances are equal. -func (source *ApplicationSource) Equals(other ApplicationSource) bool { - return reflect.DeepEqual(*source, other) +func (source *ApplicationSource) Equals(other *ApplicationSource) bool { + if source == nil && other == nil { + return true + } + if source == nil || other == nil { + return false + } + if !source.Plugin.Equals(other.Plugin) { + return false + } + // reflect.DeepEqual works fine for the other fields. Since the plugin fields are equal, set them to null so they're + // not considered in the DeepEqual comparison. + sourceCopy := source.DeepCopy() + otherCopy := other.DeepCopy() + sourceCopy.Plugin = nil + otherCopy.Plugin = nil + return reflect.DeepEqual(sourceCopy, otherCopy) } // ExplicitType returns the type (e.g. Helm, Kustomize, etc) of the application. If either none or multiple types are defined, returns an error. @@ -2540,6 +2947,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 } @@ -2547,12 +2960,17 @@ func SetK8SConfigDefaults(config *rest.Config) error { func (c *Cluster) RawRestConfig() *rest.Config { var config *rest.Config var err error - if c.Server == KubernetesInternalAPIServerAddr && os.Getenv(EnvVarFakeInClusterConfig) == "true" { + if c.Server == KubernetesInternalAPIServerAddr && env.ParseBoolFromEnv(EnvVarFakeInClusterConfig, false) { conf, exists := os.LookupEnv("KUBECONFIG") if exists { config, err = clientcmd.BuildConfigFromFlags("", conf) } else { - config, err = clientcmd.BuildConfigFromFlags("", filepath.Join(os.Getenv("HOME"), ".kube", "config")) + var homeDir string + homeDir, err = os.UserHomeDir() + if err != nil { + homeDir = "" + } + config, err = clientcmd.BuildConfigFromFlags("", filepath.Join(homeDir, ".kube", "config")) } } else if c.Server == KubernetesInternalAPIServerAddr && c.Config.Username == "" && c.Config.Password == "" && c.Config.BearerToken == "" { config, err = rest.InClusterConfig() @@ -2577,6 +2995,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, @@ -2716,5 +3137,5 @@ func (a *Application) QualifiedName() string { // RBACName returns the full qualified RBAC resource name for the application // in a backwards-compatible way. func (a *Application) RBACName(defaultNS string) string { - return security.AppRBACName(defaultNS, a.Spec.GetProject(), a.Namespace, a.Name) + return security.RBACName(defaultNS, a.Spec.GetProject(), a.Namespace, a.Name) } diff --git a/pkg/apis/application/v1alpha1/types_test.go b/pkg/apis/application/v1alpha1/types_test.go index 17f6982581db3..2374f5fb503e6 100644 --- a/pkg/apis/application/v1alpha1/types_test.go +++ b/pkg/apis/application/v1alpha1/types_test.go @@ -3,7 +3,7 @@ package v1alpha1 import ( "encoding/json" "errors" - fmt "fmt" + "fmt" "os" "path" "reflect" @@ -11,14 +11,16 @@ import ( "testing" "time" - argocdcommon "github.com/argoproj/argo-cd/v2/common" "github.com/stretchr/testify/require" "k8s.io/utils/pointer" + argocdcommon "github.com/argoproj/argo-cd/v2/common" + "github.com/argoproj/gitops-engine/pkg/sync/common" "github.com/stretchr/testify/assert" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/intstr" ) func TestAppProject_IsSourcePermitted(t *testing.T) { @@ -368,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", }}, @@ -644,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) @@ -863,9 +865,9 @@ func TestAppSourceEquality(t *testing.T) { }, } right := left.DeepCopy() - assert.True(t, left.Equals(*right)) + assert.True(t, left.Equals(right)) right.Directory.Recurse = false - assert.False(t, left.Equals(*right)) + assert.False(t, left.Equals(right)) } func TestAppDestinationEquality(t *testing.T) { @@ -1315,6 +1317,96 @@ func TestNewHelmParameter(t *testing.T) { }) } +func TestNewKustomizeReplica(t *testing.T) { + t.Run("Valid", func(t *testing.T) { + r, err := NewKustomizeReplica("my-deployment=2") + assert.NoError(t, err) + assert.Equal(t, &KustomizeReplica{Name: "my-deployment", Count: intstr.Parse("2")}, r) + }) + t.Run("InvalidFormat", func(t *testing.T) { + _, err := NewKustomizeReplica("garbage") + assert.EqualError(t, err, "expected parameter of the form: name=count. Received: garbage") + }) + t.Run("InvalidCount", func(t *testing.T) { + _, err := NewKustomizeReplica("my-deployment=garbage") + assert.EqualError(t, err, "expected integer value for count. Received: garbage") + }) +} + +func TestKustomizeReplica_GetIntCount(t *testing.T) { + t.Run("String which can be converted to integer", func(t *testing.T) { + kr := KustomizeReplica{ + Name: "test", + Count: intstr.FromString("2"), + } + count, err := kr.GetIntCount() + assert.NoError(t, err) + assert.Equal(t, 2, count) + }) + t.Run("String which cannot be converted to integer", func(t *testing.T) { + kr := KustomizeReplica{ + Name: "test", + Count: intstr.FromString("garbage"), + } + count, err := kr.GetIntCount() + assert.EqualError(t, err, "expected integer value for count. Received: garbage") + assert.Equal(t, 0, count) + }) + t.Run("Integer", func(t *testing.T) { + kr := KustomizeReplica{ + Name: "test", + Count: intstr.FromInt(2), + } + count, err := kr.GetIntCount() + assert.NoError(t, err) + assert.Equal(t, 2, count) + }) +} + +func TestApplicationSourceKustomize_MergeReplica(t *testing.T) { + r1 := KustomizeReplica{ + Name: "my-deployment", + Count: intstr.FromInt(2), + } + r2 := KustomizeReplica{ + Name: "my-deployment", + Count: intstr.FromInt(4), + } + t.Run("Add", func(t *testing.T) { + k := ApplicationSourceKustomize{Replicas: KustomizeReplicas{}} + k.MergeReplica(r1) + assert.Equal(t, KustomizeReplicas{r1}, k.Replicas) + }) + t.Run("Replace", func(t *testing.T) { + k := ApplicationSourceKustomize{Replicas: KustomizeReplicas{r1}} + k.MergeReplica(r2) + assert.Equal(t, 1, len(k.Replicas)) + assert.Equal(t, k.Replicas[0].Name, r2.Name) + assert.Equal(t, k.Replicas[0].Count, r2.Count) + }) +} +func TestApplicationSourceKustomize_FindByName(t *testing.T) { + r1 := KustomizeReplica{ + Name: "my-deployment", + Count: intstr.FromInt(2), + } + r2 := KustomizeReplica{ + Name: "my-statefulset", + Count: intstr.FromInt(4), + } + Replicas := KustomizeReplicas{r1, r2} + t.Run("Found", func(t *testing.T) { + i1 := Replicas.FindByName("my-deployment") + i2 := Replicas.FindByName("my-statefulset") + assert.Equal(t, 0, i1) + assert.Equal(t, 1, i2) + }) + t.Run("Not Found", func(t *testing.T) { + i := Replicas.FindByName("not-found") + assert.Equal(t, -1, i) + }) +} + func TestApplicationSourceHelm_IsZero(t *testing.T) { tests := []struct { name string @@ -1346,6 +1438,7 @@ func TestApplicationSourceKustomize_IsZero(t *testing.T) { {"NamePrefix", &ApplicationSourceKustomize{NamePrefix: "foo"}, false}, {"NameSuffix", &ApplicationSourceKustomize{NameSuffix: "foo"}, false}, {"Images", &ApplicationSourceKustomize{Images: []KustomizeImage{""}}, false}, + {"Replicas", &ApplicationSourceKustomize{Replicas: []KustomizeReplica{{Name: "", Count: intstr.FromInt(0)}}}, false}, {"CommonLabels", &ApplicationSourceKustomize{CommonLabels: map[string]string{"": ""}}, false}, {"CommonAnnotations", &ApplicationSourceKustomize{CommonAnnotations: map[string]string{"": ""}}, false}, } @@ -2133,6 +2226,20 @@ func TestSyncWindows_CanSync(t *testing.T) { // then assert.False(t, canSync) }) + t.Run("will allow auto sync with active-allow and inactive-allow", func(t *testing.T) { + // given + t.Parallel() + proj := newProjectBuilder(). + withActiveAllowWindow(false). + withInactiveAllowWindow(false). + build() + + // when + canSync := proj.Spec.SyncWindows.CanSync(false) + + // then + assert.True(t, canSync) + }) t.Run("will deny manual sync with active-deny", func(t *testing.T) { // given t.Parallel() @@ -2859,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", }, } @@ -2880,11 +2987,31 @@ func TestRetryStrategy_NextRetryAtCustomBackoff(t *testing.T) { } func TestSourceAllowsConcurrentProcessing_KustomizeParams(t *testing.T) { - src := ApplicationSource{Path: ".", Kustomize: &ApplicationSourceKustomize{ - NameSuffix: "test", - }} + t.Run("Has NameSuffix", func(t *testing.T) { + src := ApplicationSource{Path: ".", Kustomize: &ApplicationSourceKustomize{ + NameSuffix: "test", + }} - assert.False(t, src.AllowsConcurrentProcessing()) + assert.False(t, src.AllowsConcurrentProcessing()) + }) + + t.Run("Has CommonAnnotations", func(t *testing.T) { + src := ApplicationSource{Path: ".", Kustomize: &ApplicationSourceKustomize{ + CommonAnnotations: map[string]string{"foo": "bar"}, + }} + + assert.False(t, src.AllowsConcurrentProcessing()) + }) + + t.Run("Has Patches", func(t *testing.T) { + src := ApplicationSource{Path: ".", Kustomize: &ApplicationSourceKustomize{ + Patches: KustomizePatches{{ + Path: "test", + }}, + }} + + assert.False(t, src.AllowsConcurrentProcessing()) + }) } func TestUnSetCascadedDeletion(t *testing.T) { @@ -2948,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()) } @@ -3039,7 +3166,7 @@ func TestGetCAPath(t *testing.T) { if err != nil { panic(err) } - os.Setenv(argocdcommon.EnvVarTLSDataPath, temppath) + t.Setenv(argocdcommon.EnvVarTLSDataPath, temppath) validcert := []string{ "https://foo.example.com", "oci://foo.example.com", @@ -3261,8 +3388,8 @@ func TestApplicationSourcePluginParameters_Environ_string(t *testing.T) { func TestApplicationSourcePluginParameters_Environ_array(t *testing.T) { params := ApplicationSourcePluginParameters{ { - Name: "dependencies", - Array: []string{"redis", "minio"}, + Name: "dependencies", + OptionalArray: &OptionalArray{Array: []string{"redis", "minio"}}, }, } environ, err := params.Environ() @@ -3279,9 +3406,11 @@ func TestApplicationSourcePluginParameters_Environ_map(t *testing.T) { params := ApplicationSourcePluginParameters{ { Name: "helm-parameters", - Map: map[string]string{ - "image.repo": "quay.io/argoproj/argo-cd", - "image.tag": "v2.4.0", + OptionalMap: &OptionalMap{ + Map: map[string]string{ + "image.repo": "quay.io/argoproj/argo-cd", + "image.tag": "v2.4.0", + }, }, }, } @@ -3302,10 +3431,14 @@ func TestApplicationSourcePluginParameters_Environ_all(t *testing.T) { { Name: "some-name", String_: pointer.String("1.2.3"), - Array: []string{"redis", "minio"}, - Map: map[string]string{ - "image.repo": "quay.io/argoproj/argo-cd", - "image.tag": "v2.4.0", + OptionalArray: &OptionalArray{ + Array: []string{"redis", "minio"}, + }, + OptionalMap: &OptionalMap{ + Map: map[string]string{ + "image.repo": "quay.io/argoproj/argo-cd", + "image.tag": "v2.4.0", + }, }, }, } @@ -3401,3 +3534,89 @@ func TestGetSources(t *testing.T) { }) } } + +func TestOptionalArrayEquality(t *testing.T) { + // Demonstrate that the JSON unmarshalling of an empty array parameter is an OptionalArray with the array field set + // to an empty array. + presentButEmpty := `{"array":[]}` + param := ApplicationSourcePluginParameter{} + err := json.Unmarshal([]byte(presentButEmpty), ¶m) + require.NoError(t, err) + jsonPresentButEmpty := param.OptionalArray + require.Equal(t, &OptionalArray{Array: []string{}}, jsonPresentButEmpty) + + // We won't simulate the protobuf unmarshalling of an empty array parameter. By experimentation, this is how it's + // unmarshalled. + protobufPresentButEmpty := &OptionalArray{Array: nil} + + tests := []struct { + name string + a *OptionalArray + b *OptionalArray + expected bool + }{ + {"nil and nil", nil, nil, true}, + {"nil and empty", nil, jsonPresentButEmpty, false}, + {"nil and empty-containing-nil", nil, protobufPresentButEmpty, false}, + {"empty-containing-empty and nil", jsonPresentButEmpty, nil, false}, + {"empty-containing-nil and nil", protobufPresentButEmpty, nil, false}, + {"empty-containing-empty and empty-containing-empty", jsonPresentButEmpty, jsonPresentButEmpty, true}, + {"empty-containing-empty and empty-containing-nil", jsonPresentButEmpty, protobufPresentButEmpty, true}, + {"empty-containing-nil and empty-containing-empty", protobufPresentButEmpty, jsonPresentButEmpty, true}, + {"empty-containing-nil and empty-containing-nil", protobufPresentButEmpty, protobufPresentButEmpty, true}, + {"empty-containing-empty and non-empty", jsonPresentButEmpty, &OptionalArray{Array: []string{"a"}}, false}, + {"non-empty and empty-containing-nil", &OptionalArray{Array: []string{"a"}}, jsonPresentButEmpty, false}, + {"non-empty and non-empty", &OptionalArray{Array: []string{"a"}}, &OptionalArray{Array: []string{"a"}}, true}, + {"non-empty and non-empty different", &OptionalArray{Array: []string{"a"}}, &OptionalArray{Array: []string{"b"}}, false}, + } + for _, testCase := range tests { + testCopy := testCase + t.Run(testCopy.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, testCopy.expected, testCopy.a.Equals(testCopy.b)) + }) + } +} + +func TestOptionalMapEquality(t *testing.T) { + // Demonstrate that the JSON unmarshalling of an empty map parameter is an OptionalMap with the map field set + // to an empty map. + presentButEmpty := `{"map":{}}` + param := ApplicationSourcePluginParameter{} + err := json.Unmarshal([]byte(presentButEmpty), ¶m) + require.NoError(t, err) + jsonPresentButEmpty := param.OptionalMap + require.Equal(t, &OptionalMap{Map: map[string]string{}}, jsonPresentButEmpty) + + // We won't simulate the protobuf unmarshalling of an empty map parameter. By experimentation, this is how it's + // unmarshalled. + protobufPresentButEmpty := &OptionalMap{Map: nil} + + tests := []struct { + name string + a *OptionalMap + b *OptionalMap + expected bool + }{ + {"nil and nil", nil, nil, true}, + {"nil and empty-containing-empty", nil, jsonPresentButEmpty, false}, + {"nil and empty-containing-nil", nil, protobufPresentButEmpty, false}, + {"empty-containing-empty and nil", jsonPresentButEmpty, nil, false}, + {"empty-containing-nil and nil", protobufPresentButEmpty, nil, false}, + {"empty-containing-empty and empty-containing-empty", jsonPresentButEmpty, jsonPresentButEmpty, true}, + {"empty-containing-empty and empty-containing-nil", jsonPresentButEmpty, protobufPresentButEmpty, true}, + {"empty-containing-empty and non-empty", jsonPresentButEmpty, &OptionalMap{Map: map[string]string{"a": "b"}}, false}, + {"empty-containing-nil and empty-containing-empty", protobufPresentButEmpty, jsonPresentButEmpty, true}, + {"empty-containing-nil and empty-containing-nil", protobufPresentButEmpty, protobufPresentButEmpty, true}, + {"non-empty and empty-containing-empty", &OptionalMap{Map: map[string]string{"a": "b"}}, jsonPresentButEmpty, false}, + {"non-empty and non-empty", &OptionalMap{Map: map[string]string{"a": "b"}}, &OptionalMap{Map: map[string]string{"a": "b"}}, true}, + {"non-empty and non-empty different", &OptionalMap{Map: map[string]string{"a": "b"}}, &OptionalMap{Map: map[string]string{"a": "c"}}, false}, + } + for _, testCase := range tests { + testCopy := testCase + t.Run(testCopy.name, func(t *testing.T) { + t.Parallel() + assert.Equal(t, testCopy.expected, testCopy.a.Equals(testCopy.b)) + }) + } +} diff --git a/pkg/apis/application/v1alpha1/values.go b/pkg/apis/application/v1alpha1/values.go new file mode 100644 index 0000000000000..942e2a651cf71 --- /dev/null +++ b/pkg/apis/application/v1alpha1/values.go @@ -0,0 +1,61 @@ +package v1alpha1 + +import ( + "encoding/json" + "fmt" + reflect "reflect" + "strings" + + runtime "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/yaml" +) + +// Set the ValuesObject property to the json representation of the yaml contained in value +// Remove Values property if present +func (h *ApplicationSourceHelm) SetValuesString(value string) error { + if value == "" { + h.ValuesObject = nil + h.Values = "" + } else { + data, err := yaml.YAMLToJSON([]byte(value)) + if err != nil { + return fmt.Errorf("failed converting yaml to json: %v", err) + } + var v interface{} + if err := json.Unmarshal(data, &v); err != nil { + return fmt.Errorf("failed to unmarshal json: %v", err) + } + switch v.(type) { + case string: + case map[string]interface{}: + default: + return fmt.Errorf("invalid type %q", reflect.TypeOf(v)) + } + h.ValuesObject = &runtime.RawExtension{Raw: data} + h.Values = "" + } + return nil +} + +func (h *ApplicationSourceHelm) ValuesYAML() []byte { + if h.ValuesObject == nil || h.ValuesObject.Raw == nil { + return []byte(h.Values) + } + b, err := yaml.JSONToYAML(h.ValuesObject.Raw) + if err != nil { + // This should be impossible, because rawValue isn't set directly. + return []byte{} + } + return b +} + +func (h *ApplicationSourceHelm) ValuesIsEmpty() bool { + return len(h.ValuesYAML()) == 0 +} + +func (h *ApplicationSourceHelm) ValuesString() string { + if h.ValuesObject == nil || h.ValuesObject.Raw == nil { + return h.Values + } + return strings.TrimSuffix(string(h.ValuesYAML()), "\n") +} diff --git a/pkg/apis/application/v1alpha1/values_test.go b/pkg/apis/application/v1alpha1/values_test.go new file mode 100644 index 0000000000000..f21f17168a2e8 --- /dev/null +++ b/pkg/apis/application/v1alpha1/values_test.go @@ -0,0 +1,81 @@ +package v1alpha1 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestValues_SetString(t *testing.T) { + testCases := []struct { + name string + inputValue string + expectError bool + expectValue string + }{ + { + name: "an empty string should not throw an error", + inputValue: `""`, + expectValue: "\"\"", + }, + { + name: "a string with contents should not throw an error", + inputValue: `"hello"`, + expectValue: "hello", + }, + { + name: "an array should throw an error", + inputValue: "[]", + expectError: true, + }, + { + name: "a number should throw an error", + inputValue: "42", + expectError: true, + }, + { + name: "a boolean should throw an error", + inputValue: "false", + expectError: true, + }, + { + name: "null should throw an error", + inputValue: "null", + expectError: true, + }, + { + name: "an empty object should not throw an error", + inputValue: "{}", + expectValue: "{}", + }, + { + name: "an object with contents should not throw an error", + inputValue: `{"some": "inputValue"}`, + expectValue: "some: inputValue", + }, + { + name: "a complex object should not throw an error", + inputValue: `{"a": {"nested": "object"}, "an": ["array"], "bool": true, "number": 1, "some": "string"}`, + expectValue: "a:\n nested: object\nan:\n- array\nbool: true\nnumber: 1\nsome: string", + }, + } + + for _, testCase := range testCases { + var err error + t.Run(testCase.name, func(t *testing.T) { + source := &ApplicationSourceHelm{} + err = source.SetValuesString(testCase.inputValue) + + if !testCase.expectError { + assert.Equal(t, testCase.expectValue, source.ValuesString()) + data, err := source.ValuesObject.MarshalJSON() + assert.NoError(t, err) + err = source.ValuesObject.UnmarshalJSON(data) + assert.NoError(t, err) + assert.Equal(t, testCase.expectValue, source.ValuesString()) + } else { + assert.Error(t, err) + } + }) + } +} diff --git a/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go index 15cc07f3c19f3..8c851067a6be3 100644 --- a/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go @@ -315,6 +315,32 @@ func (in *ApplicationMatchExpression) DeepCopy() *ApplicationMatchExpression { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationPreservedFields) DeepCopyInto(out *ApplicationPreservedFields) { + *out = *in + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationPreservedFields. +func (in *ApplicationPreservedFields) DeepCopy() *ApplicationPreservedFields { + if in == nil { + return nil + } + out := new(ApplicationPreservedFields) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ApplicationSet) DeepCopyInto(out *ApplicationSet) { *out = *in @@ -431,6 +457,11 @@ func (in *ApplicationSetGenerator) DeepCopyInto(out *ApplicationSetGenerator) { *out = new(v1.LabelSelector) (*in).DeepCopyInto(*out) } + if in.Plugin != nil { + in, out := &in.Plugin, &out.Plugin + *out = new(PluginGenerator) + (*in).DeepCopyInto(*out) + } return } @@ -444,6 +475,28 @@ func (in *ApplicationSetGenerator) DeepCopy() *ApplicationSetGenerator { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in ApplicationSetIgnoreDifferences) DeepCopyInto(out *ApplicationSetIgnoreDifferences) { + { + in := &in + *out = make(ApplicationSetIgnoreDifferences, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationSetIgnoreDifferences. +func (in ApplicationSetIgnoreDifferences) DeepCopy() ApplicationSetIgnoreDifferences { + if in == nil { + return nil + } + out := new(ApplicationSetIgnoreDifferences) + in.DeepCopyInto(out) + return *out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ApplicationSetList) DeepCopyInto(out *ApplicationSetList) { *out = *in @@ -525,6 +578,11 @@ func (in *ApplicationSetNestedGenerator) DeepCopyInto(out *ApplicationSetNestedG *out = new(v1.LabelSelector) (*in).DeepCopyInto(*out) } + if in.Plugin != nil { + in, out := &in.Plugin, &out.Plugin + *out = new(PluginGenerator) + (*in).DeepCopyInto(*out) + } return } @@ -560,6 +618,32 @@ func (in ApplicationSetNestedGenerators) DeepCopy() ApplicationSetNestedGenerato return *out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApplicationSetResourceIgnoreDifferences) DeepCopyInto(out *ApplicationSetResourceIgnoreDifferences) { + *out = *in + if in.JSONPointers != nil { + in, out := &in.JSONPointers, &out.JSONPointers + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.JQPathExpressions != nil { + in, out := &in.JQPathExpressions, &out.JQPathExpressions + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationSetResourceIgnoreDifferences. +func (in *ApplicationSetResourceIgnoreDifferences) DeepCopy() *ApplicationSetResourceIgnoreDifferences { + if in == nil { + return nil + } + out := new(ApplicationSetResourceIgnoreDifferences) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ApplicationSetRolloutStep) DeepCopyInto(out *ApplicationSetRolloutStep) { *out = *in @@ -625,13 +709,35 @@ func (in *ApplicationSetSpec) DeepCopyInto(out *ApplicationSetSpec) { if in.SyncPolicy != nil { in, out := &in.SyncPolicy, &out.SyncPolicy *out = new(ApplicationSetSyncPolicy) - **out = **in + (*in).DeepCopyInto(*out) } if in.Strategy != nil { in, out := &in.Strategy, &out.Strategy *out = new(ApplicationSetStrategy) (*in).DeepCopyInto(*out) } + if in.PreservedFields != nil { + in, out := &in.PreservedFields, &out.PreservedFields + *out = new(ApplicationPreservedFields) + (*in).DeepCopyInto(*out) + } + if in.GoTemplateOptions != nil { + in, out := &in.GoTemplateOptions, &out.GoTemplateOptions + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.IgnoreApplicationDifferences != nil { + in, out := &in.IgnoreApplicationDifferences, &out.IgnoreApplicationDifferences + *out = make(ApplicationSetIgnoreDifferences, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.TemplatePatch != nil { + in, out := &in.TemplatePatch, &out.TemplatePatch + *out = new(string) + **out = **in + } return } @@ -699,6 +805,11 @@ func (in *ApplicationSetStrategy) DeepCopy() *ApplicationSetStrategy { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ApplicationSetSyncPolicy) DeepCopyInto(out *ApplicationSetSyncPolicy) { *out = *in + if in.ApplicationsSync != nil { + in, out := &in.ApplicationsSync, &out.ApplicationsSync + *out = new(ApplicationsSyncPolicy) + **out = **in + } return } @@ -798,6 +909,16 @@ func (in *ApplicationSetTerminalGenerator) DeepCopyInto(out *ApplicationSetTermi *out = new(PullRequestGenerator) (*in).DeepCopyInto(*out) } + if in.Plugin != nil { + in, out := &in.Plugin, &out.Plugin + *out = new(PluginGenerator) + (*in).DeepCopyInto(*out) + } + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } return } @@ -904,6 +1025,11 @@ func (in *ApplicationSourceHelm) DeepCopyInto(out *ApplicationSourceHelm) { *out = make([]HelmFileParameter, len(*in)) copy(*out, *in) } + if in.ValuesObject != nil { + in, out := &in.ValuesObject, &out.ValuesObject + *out = new(runtime.RawExtension) + (*in).DeepCopyInto(*out) + } return } @@ -970,6 +1096,23 @@ func (in *ApplicationSourceKustomize) DeepCopyInto(out *ApplicationSourceKustomi (*out)[key] = val } } + if in.Replicas != nil { + in, out := &in.Replicas, &out.Replicas + *out = make(KustomizeReplicas, len(*in)) + copy(*out, *in) + } + if in.Patches != nil { + in, out := &in.Patches, &out.Patches + *out = make(KustomizePatches, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Components != nil { + in, out := &in.Components, &out.Components + *out = make([]string, len(*in)) + copy(*out, *in) + } return } @@ -1025,17 +1168,15 @@ func (in *ApplicationSourcePluginParameter) DeepCopyInto(out *ApplicationSourceP *out = new(string) **out = **in } - if in.Map != nil { - in, out := &in.Map, &out.Map - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } + if in.OptionalMap != nil { + in, out := &in.OptionalMap, &out.OptionalMap + *out = new(OptionalMap) + (*in).DeepCopyInto(*out) } - if in.Array != nil { - in, out := &in.Array, &out.Array - *out = make([]string, len(*in)) - copy(*out, *in) + if in.OptionalArray != nil { + in, out := &in.OptionalArray, &out.OptionalArray + *out = new(OptionalArray) + (*in).DeepCopyInto(*out) } return } @@ -1110,7 +1251,7 @@ func (in *ApplicationSpec) DeepCopyInto(out *ApplicationSpec) { } if in.IgnoreDifferences != nil { in, out := &in.IgnoreDifferences, &out.IgnoreDifferences - *out = make([]ResourceIgnoreDifferences, len(*in)) + *out = make(IgnoreDifferences, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -1325,6 +1466,48 @@ func (in *BasicAuthBitbucketServer) DeepCopy() *BasicAuthBitbucketServer { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BearerTokenBitbucketCloud) DeepCopyInto(out *BearerTokenBitbucketCloud) { + *out = *in + if in.TokenRef != nil { + in, out := &in.TokenRef, &out.TokenRef + *out = new(SecretRef) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BearerTokenBitbucketCloud. +func (in *BearerTokenBitbucketCloud) DeepCopy() *BearerTokenBitbucketCloud { + if in == nil { + return nil + } + out := new(BearerTokenBitbucketCloud) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChartDetails) DeepCopyInto(out *ChartDetails) { + *out = *in + if in.Maintainers != nil { + in, out := &in.Maintainers, &out.Maintainers + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChartDetails. +func (in *ChartDetails) DeepCopy() *ChartDetails { + if in == nil { + return nil + } + out := new(ChartDetails) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Cluster) DeepCopyInto(out *Cluster) { *out = *in @@ -1529,6 +1712,13 @@ func (in *ComparedTo) DeepCopyInto(out *ComparedTo) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.IgnoreDifferences != nil { + in, out := &in.IgnoreDifferences, &out.IgnoreDifferences + *out = make(IgnoreDifferences, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -1751,6 +1941,13 @@ func (in *GitGenerator) DeepCopyInto(out *GitGenerator) { **out = **in } in.Template.DeepCopyInto(&out.Template) + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } @@ -1909,6 +2106,28 @@ func (in *HostResourceInfo) DeepCopy() *HostResourceInfo { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in IgnoreDifferences) DeepCopyInto(out *IgnoreDifferences) { + { + in := &in + *out = make(IgnoreDifferences, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IgnoreDifferences. +func (in IgnoreDifferences) DeepCopy() IgnoreDifferences { + if in == nil { + return nil + } + out := new(IgnoreDifferences) + in.DeepCopyInto(out) + return *out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Info) DeepCopyInto(out *Info) { *out = *in @@ -2010,6 +2229,22 @@ func (in *KnownTypeField) DeepCopy() *KnownTypeField { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KustomizeGvk) DeepCopyInto(out *KustomizeGvk) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizeGvk. +func (in *KustomizeGvk) DeepCopy() *KustomizeGvk { + if in == nil { + return nil + } + out := new(KustomizeGvk) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in KustomizeImages) DeepCopyInto(out *KustomizeImages) { { @@ -2046,6 +2281,127 @@ func (in *KustomizeOptions) DeepCopy() *KustomizeOptions { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KustomizePatch) DeepCopyInto(out *KustomizePatch) { + *out = *in + if in.Target != nil { + in, out := &in.Target, &out.Target + *out = new(KustomizeSelector) + **out = **in + } + if in.Options != nil { + in, out := &in.Options, &out.Options + *out = make(map[string]bool, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizePatch. +func (in *KustomizePatch) DeepCopy() *KustomizePatch { + if in == nil { + return nil + } + out := new(KustomizePatch) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in KustomizePatches) DeepCopyInto(out *KustomizePatches) { + { + in := &in + *out = make(KustomizePatches, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizePatches. +func (in KustomizePatches) DeepCopy() KustomizePatches { + if in == nil { + return nil + } + out := new(KustomizePatches) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KustomizeReplica) DeepCopyInto(out *KustomizeReplica) { + *out = *in + out.Count = in.Count + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizeReplica. +func (in *KustomizeReplica) DeepCopy() *KustomizeReplica { + if in == nil { + return nil + } + out := new(KustomizeReplica) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in KustomizeReplicas) DeepCopyInto(out *KustomizeReplicas) { + { + in := &in + *out = make(KustomizeReplicas, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizeReplicas. +func (in KustomizeReplicas) DeepCopy() KustomizeReplicas { + if in == nil { + return nil + } + out := new(KustomizeReplicas) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KustomizeResId) DeepCopyInto(out *KustomizeResId) { + *out = *in + out.KustomizeGvk = in.KustomizeGvk + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizeResId. +func (in *KustomizeResId) DeepCopy() *KustomizeResId { + if in == nil { + return nil + } + out := new(KustomizeResId) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KustomizeSelector) DeepCopyInto(out *KustomizeSelector) { + *out = *in + out.KustomizeResId = in.KustomizeResId + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizeSelector. +func (in *KustomizeSelector) DeepCopy() *KustomizeSelector { + if in == nil { + return nil + } + out := new(KustomizeSelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ListGenerator) DeepCopyInto(out *ListGenerator) { *out = *in @@ -2281,6 +2637,50 @@ func (in *OperationState) DeepCopy() *OperationState { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OptionalArray) DeepCopyInto(out *OptionalArray) { + *out = *in + if in.Array != nil { + in, out := &in.Array, &out.Array + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OptionalArray. +func (in *OptionalArray) DeepCopy() *OptionalArray { + if in == nil { + return nil + } + out := new(OptionalArray) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OptionalMap) DeepCopyInto(out *OptionalMap) { + *out = *in + if in.Map != nil { + in, out := &in.Map, &out.Map + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OptionalMap. +func (in *OptionalMap) DeepCopy() *OptionalMap { + if in == nil { + return nil + } + out := new(OptionalMap) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OrphanedResourceKey) DeepCopyInto(out *OrphanedResourceKey) { *out = *in @@ -2354,6 +2754,98 @@ func (in *OverrideIgnoreDiff) DeepCopy() *OverrideIgnoreDiff { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginConfigMapRef) DeepCopyInto(out *PluginConfigMapRef) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginConfigMapRef. +func (in *PluginConfigMapRef) DeepCopy() *PluginConfigMapRef { + if in == nil { + return nil + } + out := new(PluginConfigMapRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginGenerator) DeepCopyInto(out *PluginGenerator) { + *out = *in + out.ConfigMapRef = in.ConfigMapRef + in.Input.DeepCopyInto(&out.Input) + if in.RequeueAfterSeconds != nil { + in, out := &in.RequeueAfterSeconds, &out.RequeueAfterSeconds + *out = new(int64) + **out = **in + } + in.Template.DeepCopyInto(&out.Template) + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginGenerator. +func (in *PluginGenerator) DeepCopy() *PluginGenerator { + if in == nil { + return nil + } + out := new(PluginGenerator) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PluginInput) DeepCopyInto(out *PluginInput) { + *out = *in + if in.Parameters != nil { + in, out := &in.Parameters, &out.Parameters + *out = make(PluginParameters, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginInput. +func (in *PluginInput) DeepCopy() *PluginInput { + if in == nil { + return nil + } + out := new(PluginInput) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in PluginParameters) DeepCopyInto(out *PluginParameters) { + { + in := &in + *out = make(PluginParameters, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginParameters. +func (in PluginParameters) DeepCopy() PluginParameters { + if in == nil { + return nil + } + out := new(PluginParameters) + in.DeepCopyInto(out) + return *out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ProjectRole) DeepCopyInto(out *ProjectRole) { *out = *in @@ -2421,6 +2913,16 @@ func (in *PullRequestGenerator) DeepCopyInto(out *PullRequestGenerator) { **out = **in } in.Template.DeepCopyInto(&out.Template) + if in.Bitbucket != nil { + in, out := &in.Bitbucket, &out.Bitbucket + *out = new(PullRequestGeneratorBitbucket) + (*in).DeepCopyInto(*out) + } + if in.AzureDevOps != nil { + in, out := &in.AzureDevOps, &out.AzureDevOps + *out = new(PullRequestGeneratorAzureDevOps) + (*in).DeepCopyInto(*out) + } return } @@ -2434,6 +2936,58 @@ func (in *PullRequestGenerator) DeepCopy() *PullRequestGenerator { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PullRequestGeneratorAzureDevOps) DeepCopyInto(out *PullRequestGeneratorAzureDevOps) { + *out = *in + if in.TokenRef != nil { + in, out := &in.TokenRef, &out.TokenRef + *out = new(SecretRef) + **out = **in + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PullRequestGeneratorAzureDevOps. +func (in *PullRequestGeneratorAzureDevOps) DeepCopy() *PullRequestGeneratorAzureDevOps { + if in == nil { + return nil + } + out := new(PullRequestGeneratorAzureDevOps) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PullRequestGeneratorBitbucket) DeepCopyInto(out *PullRequestGeneratorBitbucket) { + *out = *in + if in.BasicAuth != nil { + in, out := &in.BasicAuth, &out.BasicAuth + *out = new(BasicAuthBitbucketServer) + (*in).DeepCopyInto(*out) + } + if in.BearerToken != nil { + in, out := &in.BearerToken, &out.BearerToken + *out = new(BearerTokenBitbucketCloud) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PullRequestGeneratorBitbucket. +func (in *PullRequestGeneratorBitbucket) DeepCopy() *PullRequestGeneratorBitbucket { + if in == nil { + return nil + } + out := new(PullRequestGeneratorBitbucket) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PullRequestGeneratorBitbucketServer) DeepCopyInto(out *PullRequestGeneratorBitbucketServer) { *out = *in @@ -2463,6 +3017,11 @@ func (in *PullRequestGeneratorFilter) DeepCopyInto(out *PullRequestGeneratorFilt *out = new(string) **out = **in } + if in.TargetBranchMatch != nil { + in, out := &in.TargetBranchMatch, &out.TargetBranchMatch + *out = new(string) + **out = **in + } return } @@ -2968,6 +3527,7 @@ func (in *ResourceNode) DeepCopy() *ResourceNode { func (in *ResourceOverride) DeepCopyInto(out *ResourceOverride) { *out = *in in.IgnoreDifferences.DeepCopyInto(&out.IgnoreDifferences) + in.IgnoreResourceUpdates.DeepCopyInto(&out.IgnoreResourceUpdates) if in.KnownTypeFields != nil { in, out := &in.KnownTypeFields, &out.KnownTypeFields *out = make([]KnownTypeField, len(*in)) @@ -3129,6 +3689,7 @@ func (in *RevisionHistory) DeepCopyInto(out *RevisionHistory) { *out = make([]string, len(*in)) copy(*out, *in) } + out.InitiatedBy = in.InitiatedBy return } @@ -3210,6 +3771,18 @@ func (in *SCMProviderGenerator) DeepCopyInto(out *SCMProviderGenerator) { **out = **in } in.Template.DeepCopyInto(&out.Template) + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.AWSCodeCommit != nil { + in, out := &in.AWSCodeCommit, &out.AWSCodeCommit + *out = new(SCMProviderGeneratorAWSCodeCommit) + (*in).DeepCopyInto(*out) + } return } @@ -3223,6 +3796,33 @@ func (in *SCMProviderGenerator) DeepCopy() *SCMProviderGenerator { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SCMProviderGeneratorAWSCodeCommit) DeepCopyInto(out *SCMProviderGeneratorAWSCodeCommit) { + *out = *in + if in.TagFilters != nil { + in, out := &in.TagFilters, &out.TagFilters + *out = make([]*TagFilter, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(TagFilter) + **out = **in + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SCMProviderGeneratorAWSCodeCommit. +func (in *SCMProviderGeneratorAWSCodeCommit) DeepCopy() *SCMProviderGeneratorAWSCodeCommit { + if in == nil { + return nil + } + out := new(SCMProviderGeneratorAWSCodeCommit) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SCMProviderGeneratorAzureDevOps) DeepCopyInto(out *SCMProviderGeneratorAzureDevOps) { *out = *in @@ -3377,6 +3977,11 @@ func (in *SCMProviderGeneratorGitlab) DeepCopyInto(out *SCMProviderGeneratorGitl *out = new(SecretRef) **out = **in } + if in.IncludeSharedProjects != nil { + in, out := &in.IncludeSharedProjects, &out.IncludeSharedProjects + *out = new(bool) + **out = **in + } return } @@ -3518,6 +4123,11 @@ func (in *SyncOperationResult) DeepCopyInto(out *SyncOperationResult) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.ManagedNamespaceMetadata != nil { + in, out := &in.ManagedNamespaceMetadata, &out.ManagedNamespaceMetadata + *out = new(ManagedNamespaceMetadata) + (*in).DeepCopyInto(*out) + } return } @@ -3771,3 +4381,19 @@ func (in *TLSClientConfig) DeepCopy() *TLSClientConfig { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TagFilter) DeepCopyInto(out *TagFilter) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TagFilter. +func (in *TagFilter) DeepCopy() *TagFilter { + if in == nil { + return nil + } + out := new(TagFilter) + in.DeepCopyInto(out) + return out +} 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/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index 115e39faa197d..5773b75ce6df2 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -21,14 +21,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index a334cbed3235a..46f64a49e41e1 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -21,14 +21,14 @@ var localSchemeBuilder = runtime.SchemeBuilder{ // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // -// import ( -// "k8s.io/client-go/kubernetes" -// clientsetscheme "k8s.io/client-go/kubernetes/scheme" -// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" -// ) +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) // -// kclientset, _ := kubernetes.NewForConfig(c) -// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. 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..1c491a584873e --- /dev/null +++ b/pkg/ratelimiter/ratelimiter.go @@ -0,0 +1,124 @@ +package ratelimiter + +import ( + "math" + "sync" + "time" + + "golang.org/x/time/rate" + "k8s.io/client-go/util/workqueue" +) + +type AppControllerRateLimiterConfig struct { + BucketSize int64 + BucketQPS float64 + FailureCoolDown time.Duration + BaseDelay time.Duration + MaxDelay time.Duration + BackoffFactor float64 +} + +func GetDefaultAppRateLimiterConfig() *AppControllerRateLimiterConfig { + return &AppControllerRateLimiterConfig{ + // global queue rate limit config + 500, + // when WORKQUEUE_BUCKET_QPS is MaxFloat64 global bucket limiting is disabled(default) + math.MaxFloat64, + // 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/clientset.go b/reposerver/apiclient/clientset.go index 1ef95466cd739..417dc758ef5bd 100644 --- a/reposerver/apiclient/clientset.go +++ b/reposerver/apiclient/clientset.go @@ -3,12 +3,12 @@ package apiclient import ( "crypto/tls" "crypto/x509" + "fmt" "time" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry" log "github.com/sirupsen/logrus" - "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" @@ -17,6 +17,8 @@ import ( "github.com/argoproj/argo-cd/v2/util/io" ) +//go:generate go run github.com/vektra/mockery/v2@v2.15.0 --name=RepoServerServiceClient + const ( // MaxGRPCMessageSize contains max grpc message size MaxGRPCMessageSize = 100 * 1024 * 1024 @@ -46,7 +48,7 @@ type clientSet struct { func (c *clientSet) NewRepoServerClient() (io.Closer, RepoServerServiceClient, error) { conn, err := NewConnection(c.address, c.timeoutSeconds, &c.tlsConfig) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to open a new connection to repo server: %w", err) } return conn, NewRepoServerServiceClient(conn), nil } @@ -64,8 +66,8 @@ func NewConnection(address string, timeoutSeconds int, tlsConfig *TLSConfigurati grpc.WithStreamInterceptor(grpc_retry.StreamClientInterceptor(retryOpts...)), grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(unaryInterceptors...)), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(MaxGRPCMessageSize), grpc.MaxCallSendMsgSize(MaxGRPCMessageSize)), - grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), - grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), + grpc.WithUnaryInterceptor(argogrpc.OTELUnaryClientInterceptor()), + grpc.WithStreamInterceptor(argogrpc.OTELStreamClientInterceptor()), } tlsC := &tls.Config{} diff --git a/reposerver/apiclient/clientset_test.go b/reposerver/apiclient/clientset_test.go new file mode 100644 index 0000000000000..617cbbd0796e5 --- /dev/null +++ b/reposerver/apiclient/clientset_test.go @@ -0,0 +1,91 @@ +package apiclient_test + +import ( + "testing" + + "github.com/argoproj/argo-cd/v2/reposerver/apiclient" + "github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks" + "github.com/stretchr/testify/assert" +) + +func TestNewRepoServerClient_CorrectClientReturned(t *testing.T) { + + mockClientset := &mocks.Clientset{ + RepoServerServiceClient: &mocks.RepoServerServiceClient{}, + } + + closer, client, err := mockClientset.NewRepoServerClient() + + assert.NoError(t, err) + assert.NotNil(t, closer) + assert.NotNil(t, client) + assert.Equal(t, mockClientset.RepoServerServiceClient, client) +} + +func TestNewRepoServerClientset_InvalidInput(t *testing.T) { + // Call the function with invalid inputs + invalidClientset := apiclient.NewRepoServerClientset("", -1, apiclient.TLSConfiguration{}) + + assert.NotNil(t, invalidClientset) + assert.Implements(t, (*apiclient.Clientset)(nil), invalidClientset) +} + +func TestNewRepoServerClientset_SuccessfulConnection(t *testing.T) { + // Call the function with valid inputs + clientset := apiclient.NewRepoServerClientset("localhost:8080", 1, apiclient.TLSConfiguration{}) + + assert.NotNil(t, clientset) + assert.Implements(t, (*apiclient.Clientset)(nil), clientset) +} + +func TestNewRepoServerClientset_SuccessfulConnectionWithTLS(t *testing.T) { + // Call the function with valid inputs + clientset := apiclient.NewRepoServerClientset("localhost:8080", 1, apiclient.TLSConfiguration{ + DisableTLS: false, + StrictValidation: true, + Certificates: nil, + }) + + assert.NotNil(t, clientset) + assert.Implements(t, (*apiclient.Clientset)(nil), clientset) +} + +func TestNewConnection_TLSWithStrictValidation(t *testing.T) { + tlsConfig := apiclient.TLSConfiguration{ + DisableTLS: false, + StrictValidation: true, + Certificates: nil, + } + + conn, err := apiclient.NewConnection("example.com:443", 10, &tlsConfig) + + assert.NoError(t, err) + assert.NotNil(t, conn) +} + +func TestNewConnection_TLSWithStrictValidationAndCertificates(t *testing.T) { + tlsConfig := apiclient.TLSConfiguration{ + DisableTLS: false, + StrictValidation: true, + Certificates: nil, + } + + conn, err := apiclient.NewConnection("example.com:443", 10, &tlsConfig) + + assert.NoError(t, err) + assert.NotNil(t, conn) +} + +func TestNewConnection_InsecureConnection(t *testing.T) { + // Create a TLS configuration with TLS disabled + tlsConfig := apiclient.TLSConfiguration{ + DisableTLS: true, + StrictValidation: false, + Certificates: nil, + } + + conn, err := apiclient.NewConnection("example.com:80", 10, &tlsConfig) + + assert.NoError(t, err) + assert.NotNil(t, conn) +} diff --git a/reposerver/apiclient/mocks/RepoServerServiceClient.go b/reposerver/apiclient/mocks/RepoServerServiceClient.go index 8c6dcfaee2b72..25337c53a6373 100644 --- a/reposerver/apiclient/mocks/RepoServerServiceClient.go +++ b/reposerver/apiclient/mocks/RepoServerServiceClient.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.14.1. DO NOT EDIT. +// Code generated by mockery v2.21.1. DO NOT EDIT. package mocks @@ -33,6 +33,10 @@ func (_m *RepoServerServiceClient) GenerateManifest(ctx context.Context, in *api ret := _m.Called(_ca...) var r0 *apiclient.ManifestResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ManifestRequest, ...grpc.CallOption) (*apiclient.ManifestResponse, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ManifestRequest, ...grpc.CallOption) *apiclient.ManifestResponse); ok { r0 = rf(ctx, in, opts...) } else { @@ -41,7 +45,6 @@ func (_m *RepoServerServiceClient) GenerateManifest(ctx context.Context, in *api } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.ManifestRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -63,6 +66,10 @@ func (_m *RepoServerServiceClient) GenerateManifestWithFiles(ctx context.Context ret := _m.Called(_ca...) var r0 apiclient.RepoServerService_GenerateManifestWithFilesClient + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) (apiclient.RepoServerService_GenerateManifestWithFilesClient, error)); ok { + return rf(ctx, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, ...grpc.CallOption) apiclient.RepoServerService_GenerateManifestWithFilesClient); ok { r0 = rf(ctx, opts...) } else { @@ -71,7 +78,6 @@ func (_m *RepoServerServiceClient) GenerateManifestWithFiles(ctx context.Context } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, ...grpc.CallOption) error); ok { r1 = rf(ctx, opts...) } else { @@ -93,6 +99,10 @@ func (_m *RepoServerServiceClient) GetAppDetails(ctx context.Context, in *apicli ret := _m.Called(_ca...) var r0 *apiclient.RepoAppDetailsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.RepoServerAppDetailsQuery, ...grpc.CallOption) (*apiclient.RepoAppDetailsResponse, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.RepoServerAppDetailsQuery, ...grpc.CallOption) *apiclient.RepoAppDetailsResponse); ok { r0 = rf(ctx, in, opts...) } else { @@ -101,7 +111,6 @@ func (_m *RepoServerServiceClient) GetAppDetails(ctx context.Context, in *apicli } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.RepoServerAppDetailsQuery, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -111,6 +120,72 @@ func (_m *RepoServerServiceClient) GetAppDetails(ctx context.Context, in *apicli return r0, r1 } +// GetGitDirectories provides a mock function with given fields: ctx, in, opts +func (_m *RepoServerServiceClient) GetGitDirectories(ctx context.Context, in *apiclient.GitDirectoriesRequest, opts ...grpc.CallOption) (*apiclient.GitDirectoriesResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *apiclient.GitDirectoriesResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.GitDirectoriesRequest, ...grpc.CallOption) (*apiclient.GitDirectoriesResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.GitDirectoriesRequest, ...grpc.CallOption) *apiclient.GitDirectoriesResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*apiclient.GitDirectoriesResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *apiclient.GitDirectoriesRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetGitFiles provides a mock function with given fields: ctx, in, opts +func (_m *RepoServerServiceClient) GetGitFiles(ctx context.Context, in *apiclient.GitFilesRequest, opts ...grpc.CallOption) (*apiclient.GitFilesResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *apiclient.GitFilesResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.GitFilesRequest, ...grpc.CallOption) (*apiclient.GitFilesResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.GitFilesRequest, ...grpc.CallOption) *apiclient.GitFilesResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*apiclient.GitFilesResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *apiclient.GitFilesRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetHelmCharts provides a mock function with given fields: ctx, in, opts func (_m *RepoServerServiceClient) GetHelmCharts(ctx context.Context, in *apiclient.HelmChartsRequest, opts ...grpc.CallOption) (*apiclient.HelmChartsResponse, error) { _va := make([]interface{}, len(opts)) @@ -123,6 +198,10 @@ func (_m *RepoServerServiceClient) GetHelmCharts(ctx context.Context, in *apicli ret := _m.Called(_ca...) var r0 *apiclient.HelmChartsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.HelmChartsRequest, ...grpc.CallOption) (*apiclient.HelmChartsResponse, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.HelmChartsRequest, ...grpc.CallOption) *apiclient.HelmChartsResponse); ok { r0 = rf(ctx, in, opts...) } else { @@ -131,7 +210,6 @@ func (_m *RepoServerServiceClient) GetHelmCharts(ctx context.Context, in *apicli } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.HelmChartsRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -141,6 +219,36 @@ func (_m *RepoServerServiceClient) GetHelmCharts(ctx context.Context, in *apicli return r0, r1 } +// GetRevisionChartDetails provides a mock function with given fields: ctx, in, opts +func (_m *RepoServerServiceClient) GetRevisionChartDetails(ctx context.Context, in *apiclient.RepoServerRevisionChartDetailsRequest, opts ...grpc.CallOption) (*v1alpha1.ChartDetails, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *v1alpha1.ChartDetails + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.RepoServerRevisionChartDetailsRequest, ...grpc.CallOption) *v1alpha1.ChartDetails); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v1alpha1.ChartDetails) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *apiclient.RepoServerRevisionChartDetailsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetRevisionMetadata provides a mock function with given fields: ctx, in, opts func (_m *RepoServerServiceClient) GetRevisionMetadata(ctx context.Context, in *apiclient.RepoServerRevisionMetadataRequest, opts ...grpc.CallOption) (*v1alpha1.RevisionMetadata, error) { _va := make([]interface{}, len(opts)) @@ -153,6 +261,10 @@ func (_m *RepoServerServiceClient) GetRevisionMetadata(ctx context.Context, in * ret := _m.Called(_ca...) var r0 *v1alpha1.RevisionMetadata + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.RepoServerRevisionMetadataRequest, ...grpc.CallOption) (*v1alpha1.RevisionMetadata, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.RepoServerRevisionMetadataRequest, ...grpc.CallOption) *v1alpha1.RevisionMetadata); ok { r0 = rf(ctx, in, opts...) } else { @@ -161,7 +273,6 @@ func (_m *RepoServerServiceClient) GetRevisionMetadata(ctx context.Context, in * } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.RepoServerRevisionMetadataRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -183,6 +294,10 @@ func (_m *RepoServerServiceClient) ListApps(ctx context.Context, in *apiclient.L ret := _m.Called(_ca...) var r0 *apiclient.AppList + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ListAppsRequest, ...grpc.CallOption) (*apiclient.AppList, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ListAppsRequest, ...grpc.CallOption) *apiclient.AppList); ok { r0 = rf(ctx, in, opts...) } else { @@ -191,7 +306,6 @@ func (_m *RepoServerServiceClient) ListApps(ctx context.Context, in *apiclient.L } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.ListAppsRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -213,6 +327,10 @@ func (_m *RepoServerServiceClient) ListPlugins(ctx context.Context, in *emptypb. ret := _m.Called(_ca...) var r0 *apiclient.PluginList + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *emptypb.Empty, ...grpc.CallOption) (*apiclient.PluginList, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *emptypb.Empty, ...grpc.CallOption) *apiclient.PluginList); ok { r0 = rf(ctx, in, opts...) } else { @@ -221,7 +339,6 @@ func (_m *RepoServerServiceClient) ListPlugins(ctx context.Context, in *emptypb. } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *emptypb.Empty, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -243,6 +360,10 @@ func (_m *RepoServerServiceClient) ListRefs(ctx context.Context, in *apiclient.L ret := _m.Called(_ca...) var r0 *apiclient.Refs + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ListRefsRequest, ...grpc.CallOption) (*apiclient.Refs, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ListRefsRequest, ...grpc.CallOption) *apiclient.Refs); ok { r0 = rf(ctx, in, opts...) } else { @@ -251,7 +372,6 @@ func (_m *RepoServerServiceClient) ListRefs(ctx context.Context, in *apiclient.L } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.ListRefsRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -273,6 +393,10 @@ func (_m *RepoServerServiceClient) ResolveRevision(ctx context.Context, in *apic ret := _m.Called(_ca...) var r0 *apiclient.ResolveRevisionResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ResolveRevisionRequest, ...grpc.CallOption) (*apiclient.ResolveRevisionResponse, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.ResolveRevisionRequest, ...grpc.CallOption) *apiclient.ResolveRevisionResponse); ok { r0 = rf(ctx, in, opts...) } else { @@ -281,7 +405,6 @@ func (_m *RepoServerServiceClient) ResolveRevision(ctx context.Context, in *apic } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.ResolveRevisionRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { @@ -303,6 +426,10 @@ func (_m *RepoServerServiceClient) TestRepository(ctx context.Context, in *apicl ret := _m.Called(_ca...) var r0 *apiclient.TestRepositoryResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *apiclient.TestRepositoryRequest, ...grpc.CallOption) (*apiclient.TestRepositoryResponse, error)); ok { + return rf(ctx, in, opts...) + } if rf, ok := ret.Get(0).(func(context.Context, *apiclient.TestRepositoryRequest, ...grpc.CallOption) *apiclient.TestRepositoryResponse); ok { r0 = rf(ctx, in, opts...) } else { @@ -311,7 +438,6 @@ func (_m *RepoServerServiceClient) TestRepository(ctx context.Context, in *apicl } } - var r1 error if rf, ok := ret.Get(1).(func(context.Context, *apiclient.TestRepositoryRequest, ...grpc.CallOption) error); ok { r1 = rf(ctx, in, opts...) } else { diff --git a/reposerver/apiclient/mocks/RepoServerService_GenerateManifestWithFilesClient.go b/reposerver/apiclient/mocks/RepoServerService_GenerateManifestWithFilesClient.go new file mode 100644 index 0000000000000..79151a7ca1f58 --- /dev/null +++ b/reposerver/apiclient/mocks/RepoServerService_GenerateManifestWithFilesClient.go @@ -0,0 +1,167 @@ +// Code generated by mockery v2.13.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + apiclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient" + + metadata "google.golang.org/grpc/metadata" + + mock "github.com/stretchr/testify/mock" +) + +// RepoServerService_GenerateManifestWithFilesClient is an autogenerated mock type for the RepoServerService_GenerateManifestWithFilesClient type +type RepoServerService_GenerateManifestWithFilesClient struct { + mock.Mock +} + +// CloseAndRecv provides a mock function with given fields: +func (_m *RepoServerService_GenerateManifestWithFilesClient) CloseAndRecv() (*apiclient.ManifestResponse, error) { + ret := _m.Called() + + var r0 *apiclient.ManifestResponse + if rf, ok := ret.Get(0).(func() *apiclient.ManifestResponse); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*apiclient.ManifestResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CloseSend provides a mock function with given fields: +func (_m *RepoServerService_GenerateManifestWithFilesClient) CloseSend() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Context provides a mock function with given fields: +func (_m *RepoServerService_GenerateManifestWithFilesClient) Context() context.Context { + ret := _m.Called() + + var r0 context.Context + if rf, ok := ret.Get(0).(func() context.Context); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(context.Context) + } + } + + return r0 +} + +// Header provides a mock function with given fields: +func (_m *RepoServerService_GenerateManifestWithFilesClient) Header() (metadata.MD, error) { + ret := _m.Called() + + var r0 metadata.MD + if rf, ok := ret.Get(0).(func() metadata.MD); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(metadata.MD) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// RecvMsg provides a mock function with given fields: m +func (_m *RepoServerService_GenerateManifestWithFilesClient) RecvMsg(m interface{}) error { + ret := _m.Called(m) + + var r0 error + if rf, ok := ret.Get(0).(func(interface{}) error); ok { + r0 = rf(m) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Send provides a mock function with given fields: _a0 +func (_m *RepoServerService_GenerateManifestWithFilesClient) Send(_a0 *apiclient.ManifestRequestWithFiles) error { + ret := _m.Called(_a0) + + var r0 error + if rf, ok := ret.Get(0).(func(*apiclient.ManifestRequestWithFiles) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SendMsg provides a mock function with given fields: m +func (_m *RepoServerService_GenerateManifestWithFilesClient) SendMsg(m interface{}) error { + ret := _m.Called(m) + + var r0 error + if rf, ok := ret.Get(0).(func(interface{}) error); ok { + r0 = rf(m) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Trailer provides a mock function with given fields: +func (_m *RepoServerService_GenerateManifestWithFilesClient) Trailer() metadata.MD { + ret := _m.Called() + + var r0 metadata.MD + if rf, ok := ret.Get(0).(func() metadata.MD); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(metadata.MD) + } + } + + return r0 +} + +type mockConstructorTestingTNewRepoServerService_GenerateManifestWithFilesClient interface { + mock.TestingT + Cleanup(func()) +} + +// NewRepoServerService_GenerateManifestWithFilesClient creates a new instance of RepoServerService_GenerateManifestWithFilesClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewRepoServerService_GenerateManifestWithFilesClient(t mockConstructorTestingTNewRepoServerService_GenerateManifestWithFilesClient) *RepoServerService_GenerateManifestWithFilesClient { + mock := &RepoServerService_GenerateManifestWithFilesClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/reposerver/apiclient/repository.pb.go b/reposerver/apiclient/repository.pb.go index f19807676943c..914a967db3dfc 100644 --- a/reposerver/apiclient/repository.pb.go +++ b/reposerver/apiclient/repository.pb.go @@ -36,26 +36,31 @@ type ManifestRequest struct { NoCache bool `protobuf:"varint,3,opt,name=noCache,proto3" json:"noCache,omitempty"` AppLabelKey string `protobuf:"bytes,4,opt,name=appLabelKey,proto3" json:"appLabelKey,omitempty"` // Name of the application for which the request is triggered - AppName string `protobuf:"bytes,5,opt,name=appName,proto3" json:"appName,omitempty"` - Namespace string `protobuf:"bytes,8,opt,name=namespace,proto3" json:"namespace,omitempty"` - ApplicationSource *v1alpha1.ApplicationSource `protobuf:"bytes,10,opt,name=applicationSource,proto3" json:"applicationSource,omitempty"` - Repos []*v1alpha1.Repository `protobuf:"bytes,11,rep,name=repos,proto3" json:"repos,omitempty"` - Plugins []*v1alpha1.ConfigManagementPlugin `protobuf:"bytes,12,rep,name=plugins,proto3" json:"plugins,omitempty"` - KustomizeOptions *v1alpha1.KustomizeOptions `protobuf:"bytes,13,opt,name=kustomizeOptions,proto3" json:"kustomizeOptions,omitempty"` - KubeVersion string `protobuf:"bytes,14,opt,name=kubeVersion,proto3" json:"kubeVersion,omitempty"` - ApiVersions []string `protobuf:"bytes,15,rep,name=apiVersions,proto3" json:"apiVersions,omitempty"` + AppName string `protobuf:"bytes,5,opt,name=appName,proto3" json:"appName,omitempty"` + Namespace string `protobuf:"bytes,8,opt,name=namespace,proto3" json:"namespace,omitempty"` + ApplicationSource *v1alpha1.ApplicationSource `protobuf:"bytes,10,opt,name=applicationSource,proto3" json:"applicationSource,omitempty"` + Repos []*v1alpha1.Repository `protobuf:"bytes,11,rep,name=repos,proto3" json:"repos,omitempty"` + // Deprecated: use sidecar plugins instead. + Plugins []*v1alpha1.ConfigManagementPlugin `protobuf:"bytes,12,rep,name=plugins,proto3" json:"plugins,omitempty"` + KustomizeOptions *v1alpha1.KustomizeOptions `protobuf:"bytes,13,opt,name=kustomizeOptions,proto3" json:"kustomizeOptions,omitempty"` + KubeVersion string `protobuf:"bytes,14,opt,name=kubeVersion,proto3" json:"kubeVersion,omitempty"` + ApiVersions []string `protobuf:"bytes,15,rep,name=apiVersions,proto3" json:"apiVersions,omitempty"` // Request to verify the signature when generating the manifests (only for Git repositories) - VerifySignature bool `protobuf:"varint,16,opt,name=verifySignature,proto3" json:"verifySignature,omitempty"` - HelmRepoCreds []*v1alpha1.RepoCreds `protobuf:"bytes,17,rep,name=helmRepoCreds,proto3" json:"helmRepoCreds,omitempty"` - NoRevisionCache bool `protobuf:"varint,18,opt,name=noRevisionCache,proto3" json:"noRevisionCache,omitempty"` - TrackingMethod string `protobuf:"bytes,19,opt,name=trackingMethod,proto3" json:"trackingMethod,omitempty"` - EnabledSourceTypes map[string]bool `protobuf:"bytes,20,rep,name=enabledSourceTypes,proto3" json:"enabledSourceTypes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` - HelmOptions *v1alpha1.HelmOptions `protobuf:"bytes,21,opt,name=helmOptions,proto3" json:"helmOptions,omitempty"` - HasMultipleSources bool `protobuf:"varint,22,opt,name=hasMultipleSources,proto3" json:"hasMultipleSources,omitempty"` - RefSources map[string]*v1alpha1.RefTarget `protobuf:"bytes,23,rep,name=refSources,proto3" json:"refSources,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:"-"` + VerifySignature bool `protobuf:"varint,16,opt,name=verifySignature,proto3" json:"verifySignature,omitempty"` + HelmRepoCreds []*v1alpha1.RepoCreds `protobuf:"bytes,17,rep,name=helmRepoCreds,proto3" json:"helmRepoCreds,omitempty"` + NoRevisionCache bool `protobuf:"varint,18,opt,name=noRevisionCache,proto3" json:"noRevisionCache,omitempty"` + TrackingMethod string `protobuf:"bytes,19,opt,name=trackingMethod,proto3" json:"trackingMethod,omitempty"` + EnabledSourceTypes map[string]bool `protobuf:"bytes,20,rep,name=enabledSourceTypes,proto3" json:"enabledSourceTypes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` + HelmOptions *v1alpha1.HelmOptions `protobuf:"bytes,21,opt,name=helmOptions,proto3" json:"helmOptions,omitempty"` + HasMultipleSources bool `protobuf:"varint,22,opt,name=hasMultipleSources,proto3" json:"hasMultipleSources,omitempty"` + RefSources map[string]*v1alpha1.RefTarget `protobuf:"bytes,23,rep,name=refSources,proto3" json:"refSources,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + // This is used to surface "source not permitted" errors for Helm repositories + ProjectSourceRepos []string `protobuf:"bytes,24,rep,name=projectSourceRepos,proto3" json:"projectSourceRepos,omitempty"` + // This is used to surface "source not permitted" errors for Helm repositories + ProjectName string `protobuf:"bytes,25,opt,name=projectName,proto3" json:"projectName,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *ManifestRequest) Reset() { *m = ManifestRequest{} } @@ -231,6 +236,20 @@ func (m *ManifestRequest) GetRefSources() map[string]*v1alpha1.RefTarget { return nil } +func (m *ManifestRequest) GetProjectSourceRepos() []string { + if m != nil { + return m.ProjectSourceRepos + } + return nil +} + +func (m *ManifestRequest) GetProjectName() string { + if m != nil { + return m.ProjectName + } + return "" +} + type ManifestRequestWithFiles struct { // Types that are valid to be assigned to Part: // *ManifestRequestWithFiles_Request @@ -1327,6 +1346,72 @@ func (m *RepoServerRevisionMetadataRequest) GetCheckSignature() bool { return false } +type RepoServerRevisionChartDetailsRequest struct { + // the repo + Repo *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"` + // the chart + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // the revision within the chart + Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RepoServerRevisionChartDetailsRequest) Reset() { *m = RepoServerRevisionChartDetailsRequest{} } +func (m *RepoServerRevisionChartDetailsRequest) String() string { return proto.CompactTextString(m) } +func (*RepoServerRevisionChartDetailsRequest) ProtoMessage() {} +func (*RepoServerRevisionChartDetailsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_dd8723cfcc820480, []int{18} +} +func (m *RepoServerRevisionChartDetailsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RepoServerRevisionChartDetailsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RepoServerRevisionChartDetailsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RepoServerRevisionChartDetailsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RepoServerRevisionChartDetailsRequest.Merge(m, src) +} +func (m *RepoServerRevisionChartDetailsRequest) XXX_Size() int { + return m.Size() +} +func (m *RepoServerRevisionChartDetailsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RepoServerRevisionChartDetailsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RepoServerRevisionChartDetailsRequest proto.InternalMessageInfo + +func (m *RepoServerRevisionChartDetailsRequest) GetRepo() *v1alpha1.Repository { + if m != nil { + return m.Repo + } + return nil +} + +func (m *RepoServerRevisionChartDetailsRequest) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *RepoServerRevisionChartDetailsRequest) GetRevision() string { + if m != nil { + return m.Revision + } + return "" +} + // HelmAppSpec contains helm app name in source repo type HelmAppSpec struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -1346,7 +1431,7 @@ func (m *HelmAppSpec) Reset() { *m = HelmAppSpec{} } func (m *HelmAppSpec) String() string { return proto.CompactTextString(m) } func (*HelmAppSpec) ProtoMessage() {} func (*HelmAppSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_dd8723cfcc820480, []int{18} + return fileDescriptor_dd8723cfcc820480, []int{19} } func (m *HelmAppSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1423,7 +1508,7 @@ func (m *KustomizeAppSpec) Reset() { *m = KustomizeAppSpec{} } func (m *KustomizeAppSpec) String() string { return proto.CompactTextString(m) } func (*KustomizeAppSpec) ProtoMessage() {} func (*KustomizeAppSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_dd8723cfcc820480, []int{19} + return fileDescriptor_dd8723cfcc820480, []int{20} } func (m *KustomizeAppSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1470,7 +1555,7 @@ func (m *DirectoryAppSpec) Reset() { *m = DirectoryAppSpec{} } func (m *DirectoryAppSpec) String() string { return proto.CompactTextString(m) } func (*DirectoryAppSpec) ProtoMessage() {} func (*DirectoryAppSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_dd8723cfcc820480, []int{20} + return fileDescriptor_dd8723cfcc820480, []int{21} } func (m *DirectoryAppSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1530,7 +1615,7 @@ func (m *ParameterAnnouncement) Reset() { *m = ParameterAnnouncement{} } func (m *ParameterAnnouncement) String() string { return proto.CompactTextString(m) } func (*ParameterAnnouncement) ProtoMessage() {} func (*ParameterAnnouncement) Descriptor() ([]byte, []int) { - return fileDescriptor_dd8723cfcc820480, []int{21} + return fileDescriptor_dd8723cfcc820480, []int{22} } func (m *ParameterAnnouncement) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1634,7 +1719,7 @@ func (m *PluginAppSpec) Reset() { *m = PluginAppSpec{} } func (m *PluginAppSpec) String() string { return proto.CompactTextString(m) } func (*PluginAppSpec) ProtoMessage() {} func (*PluginAppSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_dd8723cfcc820480, []int{22} + return fileDescriptor_dd8723cfcc820480, []int{23} } func (m *PluginAppSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1681,7 +1766,7 @@ func (m *HelmChartsRequest) Reset() { *m = HelmChartsRequest{} } func (m *HelmChartsRequest) String() string { return proto.CompactTextString(m) } func (*HelmChartsRequest) ProtoMessage() {} func (*HelmChartsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_dd8723cfcc820480, []int{23} + return fileDescriptor_dd8723cfcc820480, []int{24} } func (m *HelmChartsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1729,7 +1814,7 @@ func (m *HelmChart) Reset() { *m = HelmChart{} } func (m *HelmChart) String() string { return proto.CompactTextString(m) } func (*HelmChart) ProtoMessage() {} func (*HelmChart) Descriptor() ([]byte, []int) { - return fileDescriptor_dd8723cfcc820480, []int{24} + return fileDescriptor_dd8723cfcc820480, []int{25} } func (m *HelmChart) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1783,7 +1868,7 @@ func (m *HelmChartsResponse) Reset() { *m = HelmChartsResponse{} } func (m *HelmChartsResponse) String() string { return proto.CompactTextString(m) } func (*HelmChartsResponse) ProtoMessage() {} func (*HelmChartsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_dd8723cfcc820480, []int{25} + return fileDescriptor_dd8723cfcc820480, []int{26} } func (m *HelmChartsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1819,6 +1904,260 @@ func (m *HelmChartsResponse) GetItems() []*HelmChart { return nil } +type GitFilesRequest 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"` + 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:"-"` +} + +func (m *GitFilesRequest) Reset() { *m = GitFilesRequest{} } +func (m *GitFilesRequest) String() string { return proto.CompactTextString(m) } +func (*GitFilesRequest) ProtoMessage() {} +func (*GitFilesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_dd8723cfcc820480, []int{27} +} +func (m *GitFilesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GitFilesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GitFilesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GitFilesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GitFilesRequest.Merge(m, src) +} +func (m *GitFilesRequest) XXX_Size() int { + return m.Size() +} +func (m *GitFilesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GitFilesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GitFilesRequest proto.InternalMessageInfo + +func (m *GitFilesRequest) GetRepo() *v1alpha1.Repository { + if m != nil { + return m.Repo + } + return nil +} + +func (m *GitFilesRequest) GetSubmoduleEnabled() bool { + if m != nil { + return m.SubmoduleEnabled + } + return false +} + +func (m *GitFilesRequest) GetRevision() string { + if m != nil { + return m.Revision + } + return "" +} + +func (m *GitFilesRequest) GetPath() string { + if m != nil { + return m.Path + } + return "" +} + +func (m *GitFilesRequest) GetNewGitFileGlobbingEnabled() bool { + if m != nil { + return m.NewGitFileGlobbingEnabled + } + 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"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GitFilesResponse) Reset() { *m = GitFilesResponse{} } +func (m *GitFilesResponse) String() string { return proto.CompactTextString(m) } +func (*GitFilesResponse) ProtoMessage() {} +func (*GitFilesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_dd8723cfcc820480, []int{28} +} +func (m *GitFilesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GitFilesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GitFilesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GitFilesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GitFilesResponse.Merge(m, src) +} +func (m *GitFilesResponse) XXX_Size() int { + return m.Size() +} +func (m *GitFilesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GitFilesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GitFilesResponse proto.InternalMessageInfo + +func (m *GitFilesResponse) GetMap() map[string][]byte { + if m != nil { + return m.Map + } + return nil +} + +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:"-"` +} + +func (m *GitDirectoriesRequest) Reset() { *m = GitDirectoriesRequest{} } +func (m *GitDirectoriesRequest) String() string { return proto.CompactTextString(m) } +func (*GitDirectoriesRequest) ProtoMessage() {} +func (*GitDirectoriesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_dd8723cfcc820480, []int{29} +} +func (m *GitDirectoriesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GitDirectoriesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GitDirectoriesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GitDirectoriesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GitDirectoriesRequest.Merge(m, src) +} +func (m *GitDirectoriesRequest) XXX_Size() int { + return m.Size() +} +func (m *GitDirectoriesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GitDirectoriesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GitDirectoriesRequest proto.InternalMessageInfo + +func (m *GitDirectoriesRequest) GetRepo() *v1alpha1.Repository { + if m != nil { + return m.Repo + } + return nil +} + +func (m *GitDirectoriesRequest) GetSubmoduleEnabled() bool { + if m != nil { + return m.SubmoduleEnabled + } + return false +} + +func (m *GitDirectoriesRequest) GetRevision() string { + if m != nil { + return m.Revision + } + 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"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *GitDirectoriesResponse) Reset() { *m = GitDirectoriesResponse{} } +func (m *GitDirectoriesResponse) String() string { return proto.CompactTextString(m) } +func (*GitDirectoriesResponse) ProtoMessage() {} +func (*GitDirectoriesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_dd8723cfcc820480, []int{30} +} +func (m *GitDirectoriesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GitDirectoriesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GitDirectoriesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GitDirectoriesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GitDirectoriesResponse.Merge(m, src) +} +func (m *GitDirectoriesResponse) XXX_Size() int { + return m.Size() +} +func (m *GitDirectoriesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GitDirectoriesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GitDirectoriesResponse proto.InternalMessageInfo + +func (m *GitDirectoriesResponse) GetPaths() []string { + if m != nil { + return m.Paths + } + return nil +} + func init() { proto.RegisterType((*ManifestRequest)(nil), "repository.ManifestRequest") proto.RegisterMapType((map[string]bool)(nil), "repository.ManifestRequest.EnabledSourceTypesEntry") @@ -1844,6 +2183,7 @@ func init() { proto.RegisterMapType((map[string]*v1alpha1.RefTarget)(nil), "repository.RepoServerAppDetailsQuery.RefSourcesEntry") proto.RegisterType((*RepoAppDetailsResponse)(nil), "repository.RepoAppDetailsResponse") proto.RegisterType((*RepoServerRevisionMetadataRequest)(nil), "repository.RepoServerRevisionMetadataRequest") + proto.RegisterType((*RepoServerRevisionChartDetailsRequest)(nil), "repository.RepoServerRevisionChartDetailsRequest") proto.RegisterType((*HelmAppSpec)(nil), "repository.HelmAppSpec") proto.RegisterType((*KustomizeAppSpec)(nil), "repository.KustomizeAppSpec") proto.RegisterType((*DirectoryAppSpec)(nil), "repository.DirectoryAppSpec") @@ -1853,6 +2193,11 @@ func init() { proto.RegisterType((*HelmChartsRequest)(nil), "repository.HelmChartsRequest") proto.RegisterType((*HelmChart)(nil), "repository.HelmChart") proto.RegisterType((*HelmChartsResponse)(nil), "repository.HelmChartsResponse") + proto.RegisterType((*GitFilesRequest)(nil), "repository.GitFilesRequest") + proto.RegisterType((*GitFilesResponse)(nil), "repository.GitFilesResponse") + proto.RegisterMapType((map[string][]byte)(nil), "repository.GitFilesResponse.MapEntry") + proto.RegisterType((*GitDirectoriesRequest)(nil), "repository.GitDirectoriesRequest") + proto.RegisterType((*GitDirectoriesResponse)(nil), "repository.GitDirectoriesResponse") } func init() { @@ -1860,124 +2205,140 @@ func init() { } var fileDescriptor_dd8723cfcc820480 = []byte{ - // 1870 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x19, 0xdb, 0x6e, 0x1c, 0x49, - 0xd5, 0x73, 0xb1, 0x3d, 0x73, 0x9c, 0xf8, 0x52, 0x49, 0x9c, 0xce, 0x6c, 0xd6, 0xf2, 0x36, 0x10, - 0x99, 0xcd, 0x6e, 0x8f, 0xe2, 0x68, 0x77, 0x51, 0x16, 0x16, 0x79, 0xbd, 0x49, 0x1c, 0x25, 0x4e, - 0x4c, 0x27, 0x80, 0x16, 0x02, 0xa8, 0xdc, 0x53, 0xd3, 0x53, 0x3b, 0x7d, 0xa9, 0x74, 0x57, 0x0f, - 0x9a, 0x48, 0x3c, 0x20, 0x21, 0x24, 0x7e, 0x00, 0xf1, 0x27, 0x3c, 0xf2, 0xc4, 0xe5, 0x11, 0xf1, - 0x03, 0xa0, 0x7c, 0x09, 0xaa, 0x4b, 0x5f, 0xa7, 0xed, 0x64, 0x35, 0x8e, 0xf7, 0x61, 0x5f, 0xec, - 0xae, 0x53, 0xe7, 0x56, 0xa7, 0xce, 0xb5, 0x06, 0x6e, 0x44, 0x84, 0x85, 0x31, 0x89, 0x26, 0x24, - 0xea, 0xcb, 0x4f, 0xca, 0xc3, 0x68, 0x5a, 0xf8, 0xb4, 0x58, 0x14, 0xf2, 0x10, 0x41, 0x0e, 0xe9, - 0x3d, 0x72, 0x29, 0x1f, 0x25, 0xc7, 0x96, 0x13, 0xfa, 0x7d, 0x1c, 0xb9, 0x21, 0x8b, 0xc2, 0xaf, - 0xe4, 0xc7, 0x87, 0xce, 0xa0, 0x3f, 0xd9, 0xed, 0xb3, 0xb1, 0xdb, 0xc7, 0x8c, 0xc6, 0x7d, 0xcc, - 0x98, 0x47, 0x1d, 0xcc, 0x69, 0x18, 0xf4, 0x27, 0xb7, 0xb0, 0xc7, 0x46, 0xf8, 0x56, 0xdf, 0x25, - 0x01, 0x89, 0x30, 0x27, 0x03, 0xc5, 0xb9, 0xf7, 0x8e, 0x1b, 0x86, 0xae, 0x47, 0xfa, 0x72, 0x75, - 0x9c, 0x0c, 0xfb, 0xc4, 0x67, 0x5c, 0x8b, 0x35, 0xff, 0x72, 0x01, 0xd6, 0x0e, 0x71, 0x40, 0x87, - 0x24, 0xe6, 0x36, 0x79, 0x91, 0x90, 0x98, 0xa3, 0xe7, 0xd0, 0x16, 0xca, 0x18, 0x8d, 0xed, 0xc6, - 0xce, 0xca, 0xee, 0x81, 0x95, 0x6b, 0x63, 0xa5, 0xda, 0xc8, 0x8f, 0xdf, 0x38, 0x03, 0x6b, 0xb2, - 0x6b, 0xb1, 0xb1, 0x6b, 0x09, 0x6d, 0xac, 0x82, 0x36, 0x56, 0xaa, 0x8d, 0x65, 0x67, 0xc7, 0xb2, - 0x25, 0x57, 0xd4, 0x83, 0x4e, 0x44, 0x26, 0x34, 0xa6, 0x61, 0x60, 0x34, 0xb7, 0x1b, 0x3b, 0x5d, - 0x3b, 0x5b, 0x23, 0x03, 0x96, 0x83, 0x70, 0x1f, 0x3b, 0x23, 0x62, 0xb4, 0xb6, 0x1b, 0x3b, 0x1d, - 0x3b, 0x5d, 0xa2, 0x6d, 0x58, 0xc1, 0x8c, 0x3d, 0xc2, 0xc7, 0xc4, 0x7b, 0x48, 0xa6, 0x46, 0x5b, - 0x12, 0x16, 0x41, 0x82, 0x16, 0x33, 0xf6, 0x18, 0xfb, 0xc4, 0x58, 0x94, 0xbb, 0xe9, 0x12, 0x5d, - 0x87, 0x6e, 0x80, 0x7d, 0x12, 0x33, 0xec, 0x10, 0xa3, 0x23, 0xf7, 0x72, 0x00, 0xfa, 0x1d, 0x6c, - 0x14, 0x14, 0x7f, 0x1a, 0x26, 0x91, 0x43, 0x0c, 0x90, 0x47, 0x7f, 0x32, 0xdf, 0xd1, 0xf7, 0xaa, - 0x6c, 0xed, 0x59, 0x49, 0xe8, 0xd7, 0xb0, 0x28, 0x6f, 0xde, 0x58, 0xd9, 0x6e, 0x9d, 0xa9, 0xb5, - 0x15, 0x5b, 0x14, 0xc0, 0x32, 0xf3, 0x12, 0x97, 0x06, 0xb1, 0x71, 0x41, 0x4a, 0x78, 0x36, 0x9f, - 0x84, 0xfd, 0x30, 0x18, 0x52, 0xf7, 0x10, 0x07, 0xd8, 0x25, 0x3e, 0x09, 0xf8, 0x91, 0x64, 0x6e, - 0xa7, 0x42, 0xd0, 0x4b, 0x58, 0x1f, 0x27, 0x31, 0x0f, 0x7d, 0xfa, 0x92, 0x3c, 0x61, 0x82, 0x36, - 0x36, 0x2e, 0x4a, 0x6b, 0x3e, 0x9e, 0x4f, 0xf0, 0xc3, 0x0a, 0x57, 0x7b, 0x46, 0x8e, 0x70, 0x92, - 0x71, 0x72, 0x4c, 0x7e, 0x46, 0x22, 0xe9, 0x5d, 0xab, 0xca, 0x49, 0x0a, 0x20, 0xe5, 0x46, 0x54, - 0xaf, 0x62, 0x63, 0x6d, 0xbb, 0xa5, 0xdc, 0x28, 0x03, 0xa1, 0x1d, 0x58, 0x9b, 0x90, 0x88, 0x0e, - 0xa7, 0x4f, 0xa9, 0x1b, 0x60, 0x9e, 0x44, 0xc4, 0x58, 0x97, 0xae, 0x58, 0x05, 0x23, 0x1f, 0x2e, - 0x8e, 0x88, 0xe7, 0x0b, 0x93, 0xef, 0x47, 0x64, 0x10, 0x1b, 0x1b, 0xd2, 0xbe, 0xf7, 0xe7, 0xbf, - 0x41, 0xc9, 0xce, 0x2e, 0x73, 0x17, 0x8a, 0x05, 0xa1, 0xad, 0x23, 0x45, 0xc5, 0x08, 0x52, 0x8a, - 0x55, 0xc0, 0xe8, 0x06, 0xac, 0xf2, 0x08, 0x3b, 0x63, 0x1a, 0xb8, 0x87, 0x84, 0x8f, 0xc2, 0x81, - 0x71, 0x49, 0x5a, 0xa2, 0x02, 0x45, 0x0e, 0x20, 0x12, 0xe0, 0x63, 0x8f, 0x0c, 0x94, 0x2f, 0x3e, - 0x9b, 0x32, 0x12, 0x1b, 0x97, 0xe5, 0x29, 0x6e, 0x5b, 0x85, 0x0c, 0x55, 0x49, 0x10, 0xd6, 0xdd, - 0x19, 0xaa, 0xbb, 0x01, 0x8f, 0xa6, 0x76, 0x0d, 0x3b, 0x34, 0x86, 0x15, 0x71, 0x8e, 0xd4, 0x15, - 0xae, 0x48, 0x57, 0x78, 0x30, 0x9f, 0x8d, 0x0e, 0x72, 0x86, 0x76, 0x91, 0x3b, 0xb2, 0x00, 0x8d, - 0x70, 0x7c, 0x98, 0x78, 0x9c, 0x32, 0x8f, 0x28, 0x35, 0x62, 0x63, 0x53, 0x9a, 0xa9, 0x66, 0x07, - 0x3d, 0x04, 0x88, 0xc8, 0x30, 0xc5, 0xbb, 0x2a, 0x4f, 0x7e, 0xf3, 0xb4, 0x93, 0xdb, 0x19, 0xb6, - 0x3a, 0x71, 0x81, 0xbc, 0x77, 0x17, 0xae, 0x9e, 0x60, 0x18, 0xb4, 0x0e, 0xad, 0x31, 0x99, 0xca, - 0x84, 0xda, 0xb5, 0xc5, 0x27, 0xba, 0x0c, 0x8b, 0x13, 0xec, 0x25, 0x44, 0xa6, 0xc0, 0x8e, 0xad, - 0x16, 0x77, 0x9a, 0x3f, 0x68, 0xf4, 0xfe, 0xd8, 0x80, 0xb5, 0x8a, 0x98, 0x1a, 0xfa, 0x5f, 0x15, - 0xe9, 0xcf, 0xc0, 0xe9, 0x86, 0xcf, 0x70, 0xe4, 0x12, 0x5e, 0x50, 0xc4, 0xfc, 0x4f, 0x03, 0x8c, - 0xca, 0xf9, 0x7f, 0x4e, 0xf9, 0xe8, 0x1e, 0xf5, 0x48, 0x8c, 0x3e, 0x81, 0xe5, 0x48, 0xc1, 0x74, - 0x99, 0x78, 0xe7, 0x14, 0xb3, 0x1d, 0x2c, 0xd8, 0x29, 0x36, 0xfa, 0x0c, 0x3a, 0x3e, 0xe1, 0x78, - 0x80, 0x39, 0xd6, 0xba, 0x6f, 0xd7, 0x51, 0x0a, 0x29, 0x87, 0x1a, 0xef, 0x60, 0xc1, 0xce, 0x68, - 0xd0, 0x47, 0xb0, 0xe8, 0x8c, 0x92, 0x60, 0x2c, 0x0b, 0xc4, 0xca, 0xee, 0xbb, 0x27, 0x11, 0xef, - 0x0b, 0xa4, 0x83, 0x05, 0x5b, 0x61, 0x7f, 0xbe, 0x04, 0x6d, 0x86, 0x23, 0x6e, 0xde, 0x83, 0xcb, - 0x75, 0x22, 0x44, 0x55, 0x72, 0x46, 0xc4, 0x19, 0xc7, 0x89, 0xaf, 0xcd, 0x9c, 0xad, 0x11, 0x82, - 0x76, 0x4c, 0x5f, 0x2a, 0x53, 0xb7, 0x6c, 0xf9, 0x6d, 0x7e, 0x1f, 0x36, 0x66, 0xa4, 0x89, 0x4b, - 0x55, 0xba, 0x09, 0x0e, 0x17, 0xb4, 0x68, 0x33, 0x81, 0x2b, 0xcf, 0xa4, 0x2d, 0xb2, 0xd4, 0x7c, - 0x1e, 0x75, 0xd6, 0x3c, 0x80, 0xcd, 0xaa, 0xd8, 0x98, 0x85, 0x41, 0x4c, 0x44, 0x94, 0xc8, 0x5c, - 0x46, 0xc9, 0x20, 0xdf, 0x95, 0x5a, 0x74, 0xec, 0x9a, 0x1d, 0xf3, 0xf7, 0x4d, 0xd8, 0xb4, 0x49, - 0x1c, 0x7a, 0x13, 0x92, 0x26, 0x9a, 0xf3, 0x69, 0x15, 0x7e, 0x09, 0x2d, 0xcc, 0x98, 0x76, 0x93, - 0x07, 0x67, 0x56, 0x8c, 0x6d, 0xc1, 0x15, 0x7d, 0x00, 0x1b, 0xd8, 0x3f, 0xa6, 0x6e, 0x12, 0x26, - 0x71, 0x7a, 0x2c, 0xe9, 0x54, 0x5d, 0x7b, 0x76, 0xc3, 0x74, 0xe0, 0xea, 0x8c, 0x09, 0xb4, 0x39, - 0x8b, 0x0d, 0x4d, 0xa3, 0xd2, 0xd0, 0xd4, 0x0a, 0x69, 0x9e, 0x24, 0xe4, 0x1f, 0x0d, 0x58, 0xcf, - 0x43, 0x47, 0xb3, 0xbf, 0x0e, 0x5d, 0x5f, 0xc3, 0x62, 0xa3, 0x21, 0x0b, 0x56, 0x0e, 0x28, 0xf7, - 0x36, 0xcd, 0x6a, 0x6f, 0xb3, 0x09, 0x4b, 0xaa, 0xf5, 0xd4, 0x07, 0xd3, 0xab, 0x92, 0xca, 0xed, - 0x8a, 0xca, 0x5b, 0x00, 0x71, 0x96, 0xbf, 0x8c, 0x25, 0xb9, 0x5b, 0x80, 0x20, 0x13, 0x2e, 0xa8, - 0x4a, 0x68, 0x93, 0x38, 0xf1, 0xb8, 0xb1, 0x2c, 0x31, 0x4a, 0x30, 0x33, 0x84, 0xb5, 0x47, 0x54, - 0x9c, 0x61, 0x18, 0x9f, 0x8f, 0xb3, 0x7f, 0x0c, 0x6d, 0x21, 0x4c, 0x1c, 0xec, 0x38, 0xc2, 0x81, - 0x33, 0x22, 0xa9, 0xad, 0xb2, 0xb5, 0x08, 0x63, 0x8e, 0xdd, 0xd8, 0x68, 0x4a, 0xb8, 0xfc, 0x36, - 0xff, 0xda, 0x54, 0x9a, 0xee, 0x31, 0x16, 0x7f, 0xf3, 0xed, 0x6f, 0x7d, 0x41, 0x6e, 0xcd, 0x16, - 0xe4, 0x8a, 0xca, 0x5f, 0xa7, 0x20, 0x9f, 0x51, 0x99, 0x32, 0x13, 0x58, 0xde, 0x63, 0x4c, 0x28, - 0x82, 0x6e, 0x41, 0x1b, 0x33, 0xa6, 0x0c, 0x5e, 0xc9, 0xc8, 0x1a, 0x45, 0xfc, 0xd7, 0x2a, 0x49, - 0xd4, 0xde, 0x27, 0xd0, 0xcd, 0x40, 0xaf, 0x13, 0xdb, 0x2d, 0x8a, 0xdd, 0x06, 0x50, 0x1d, 0xe7, - 0x83, 0x60, 0x18, 0x8a, 0x2b, 0x15, 0xce, 0xae, 0x49, 0xe5, 0xb7, 0x79, 0x27, 0xc5, 0x90, 0xba, - 0x7d, 0x00, 0x8b, 0x94, 0x13, 0x3f, 0x55, 0x6e, 0xb3, 0xa8, 0x5c, 0xce, 0xc8, 0x56, 0x48, 0xe6, - 0x3f, 0x3b, 0x70, 0x4d, 0xdc, 0xd8, 0x53, 0x19, 0x26, 0x7b, 0x8c, 0x7d, 0x41, 0x38, 0xa6, 0x5e, - 0xfc, 0x93, 0x84, 0x44, 0xd3, 0xb7, 0xec, 0x18, 0x2e, 0x2c, 0xa9, 0x28, 0xd3, 0xf9, 0xee, 0xcc, - 0x87, 0x0f, 0xcd, 0x3e, 0x9f, 0x38, 0x5a, 0x6f, 0x67, 0xe2, 0xa8, 0x9b, 0x00, 0xda, 0xe7, 0x34, - 0x01, 0x9c, 0x3c, 0x04, 0x16, 0x46, 0xcb, 0xa5, 0xf2, 0x68, 0x59, 0xd3, 0x58, 0x2f, 0xbf, 0x69, - 0x63, 0xdd, 0xa9, 0x6d, 0xac, 0xfd, 0xda, 0x38, 0xee, 0x4a, 0x73, 0xff, 0xa8, 0xe8, 0x81, 0x27, - 0xfa, 0xda, 0x3c, 0x2d, 0x36, 0xbc, 0xd5, 0x16, 0xfb, 0xa7, 0xa5, 0x96, 0x59, 0x0d, 0xad, 0x1f, - 0xbd, 0xd9, 0x99, 0xbe, 0x4d, 0xcd, 0xf3, 0x1f, 0x64, 0xcf, 0xc4, 0xc2, 0xdc, 0x06, 0x59, 0x41, - 0x17, 0x75, 0x48, 0x94, 0x56, 0x9d, 0xb4, 0xc4, 0x37, 0xba, 0x09, 0x6d, 0x61, 0x64, 0xdd, 0xd4, - 0x5e, 0x2d, 0xda, 0x53, 0xdc, 0xc4, 0x1e, 0x63, 0x4f, 0x19, 0x71, 0x6c, 0x89, 0x84, 0xee, 0x40, - 0x37, 0x73, 0x7c, 0x1d, 0x59, 0xd7, 0x8b, 0x14, 0x59, 0x9c, 0xa4, 0x64, 0x39, 0xba, 0xa0, 0x1d, - 0xd0, 0x88, 0x38, 0xb2, 0xe5, 0x5b, 0x9c, 0xa5, 0xfd, 0x22, 0xdd, 0xcc, 0x68, 0x33, 0x74, 0x74, - 0x0b, 0x96, 0xd4, 0x94, 0x2f, 0x23, 0x68, 0x65, 0xf7, 0xda, 0x6c, 0x32, 0x4d, 0xa9, 0x34, 0xa2, - 0xf9, 0xf7, 0x06, 0xbc, 0x97, 0x3b, 0x44, 0x1a, 0x4d, 0x69, 0xd7, 0xfd, 0xcd, 0x57, 0xdc, 0x1b, - 0xb0, 0x2a, 0xdb, 0xfc, 0x7c, 0xd8, 0x57, 0xef, 0x4e, 0x15, 0xa8, 0xf9, 0xb7, 0x26, 0xac, 0x14, - 0x2e, 0xa2, 0xae, 0xf0, 0x88, 0xc6, 0x49, 0xde, 0xbf, 0x1c, 0x90, 0x64, 0x72, 0xed, 0xda, 0x05, - 0x08, 0x1a, 0x03, 0x30, 0x1c, 0x61, 0x9f, 0x70, 0x12, 0x89, 0x8c, 0x28, 0x22, 0xe7, 0xe1, 0xfc, - 0x51, 0x7a, 0x94, 0xf2, 0xb4, 0x0b, 0xec, 0x45, 0xe7, 0x27, 0x45, 0xc7, 0x3a, 0x0f, 0xea, 0x15, - 0xfa, 0x2d, 0xac, 0x0e, 0xa9, 0x47, 0x8e, 0x72, 0x45, 0x96, 0xa4, 0x22, 0x4f, 0xe6, 0x57, 0xe4, - 0x5e, 0x91, 0xaf, 0x5d, 0x11, 0x63, 0xbe, 0x0f, 0xeb, 0x55, 0xbf, 0x14, 0x4a, 0x52, 0x1f, 0xbb, - 0x99, 0xb5, 0xf4, 0xca, 0x44, 0xb0, 0x5e, 0xf5, 0x43, 0xf3, 0xbf, 0x4d, 0xb8, 0x92, 0xb1, 0xdb, - 0x0b, 0x82, 0x30, 0x09, 0x1c, 0xf9, 0x00, 0x55, 0x7b, 0x17, 0x97, 0x61, 0x91, 0x53, 0xee, 0x65, - 0x0d, 0x84, 0x5c, 0x88, 0x1a, 0xc0, 0xc3, 0xd0, 0xe3, 0x94, 0xe9, 0x7e, 0x38, 0x5d, 0x2a, 0x1f, - 0x79, 0x91, 0xd0, 0x88, 0x0c, 0x64, 0x44, 0x75, 0xec, 0x6c, 0x2d, 0xf6, 0x44, 0x77, 0x20, 0xdb, - 0x61, 0x65, 0xcc, 0x6c, 0x2d, 0xfd, 0x27, 0xf4, 0x3c, 0xe2, 0x08, 0x73, 0x14, 0x1a, 0xe6, 0x0a, - 0x54, 0x36, 0xe2, 0x3c, 0xa2, 0x81, 0xab, 0xdb, 0x65, 0xbd, 0x12, 0x7a, 0xe2, 0x28, 0xc2, 0x53, - 0xa3, 0x23, 0x0d, 0xa0, 0x16, 0xe8, 0x87, 0xd0, 0xf2, 0x31, 0xd3, 0x05, 0xe3, 0xfd, 0x52, 0x94, - 0xd5, 0x59, 0xc0, 0x3a, 0xc4, 0x4c, 0x65, 0x54, 0x41, 0xd6, 0xfb, 0x18, 0x3a, 0x29, 0xe0, 0x6b, - 0xb5, 0x56, 0x5f, 0xc1, 0xc5, 0x52, 0x10, 0xa3, 0x2f, 0x61, 0x33, 0xf7, 0xa8, 0xa2, 0x40, 0xdd, - 0x4c, 0xbd, 0xf7, 0x5a, 0xcd, 0xec, 0x13, 0x18, 0x98, 0x2f, 0x60, 0x43, 0xb8, 0xcc, 0xfe, 0x08, - 0x47, 0xfc, 0x9c, 0x46, 0x84, 0x4f, 0xa1, 0x9b, 0x89, 0xac, 0xf5, 0x99, 0x1e, 0x74, 0x26, 0xe9, - 0xc3, 0xa0, 0x9a, 0x11, 0xb2, 0xb5, 0xb9, 0x07, 0xa8, 0xa8, 0xaf, 0xce, 0xe4, 0x37, 0xcb, 0xcd, - 0xe5, 0x95, 0x6a, 0xda, 0x96, 0xe8, 0xba, 0xb7, 0xdc, 0xfd, 0xd3, 0x32, 0x6c, 0xe4, 0xa9, 0x50, - 0xfc, 0xa5, 0x0e, 0x41, 0x4f, 0x60, 0xfd, 0xbe, 0x7e, 0xaf, 0x4f, 0x27, 0x3f, 0x74, 0xda, 0x53, - 0x4a, 0xef, 0x7a, 0xfd, 0xa6, 0xd2, 0xc8, 0x5c, 0x40, 0x0e, 0x5c, 0xab, 0x32, 0xcc, 0x5f, 0x6d, - 0xbe, 0x7b, 0x0a, 0xe7, 0x0c, 0xeb, 0x75, 0x22, 0x76, 0x1a, 0xe8, 0x4b, 0x58, 0x2d, 0xbf, 0x2d, - 0xa0, 0x92, 0x2f, 0xd4, 0x3e, 0x77, 0xf4, 0xcc, 0xd3, 0x50, 0x32, 0xfd, 0x9f, 0x8b, 0x02, 0x5e, - 0x1a, 0xb4, 0x91, 0x59, 0x6e, 0x2f, 0xea, 0x1e, 0x22, 0x7a, 0xdf, 0x39, 0x15, 0x27, 0xe3, 0xfe, - 0x29, 0x74, 0xd2, 0xc1, 0xb4, 0x6c, 0xe6, 0xca, 0xb8, 0xda, 0x5b, 0x2f, 0xf3, 0x1b, 0xc6, 0xe6, - 0x02, 0xfa, 0x4c, 0x11, 0x8b, 0xc1, 0x65, 0x96, 0xb8, 0x30, 0x8e, 0xf5, 0x2e, 0xd5, 0x8c, 0x40, - 0xe6, 0x02, 0xfa, 0x31, 0xac, 0x88, 0xaf, 0x23, 0xfd, 0x52, 0xbe, 0x69, 0xa9, 0x1f, 0x66, 0xac, - 0xf4, 0x87, 0x19, 0xeb, 0xae, 0xcf, 0xf8, 0xb4, 0x57, 0x33, 0xa3, 0x68, 0x06, 0xcf, 0xe1, 0xe2, - 0x7d, 0xc2, 0xf3, 0x96, 0x02, 0x7d, 0xef, 0x8d, 0x1a, 0xaf, 0x9e, 0x59, 0x45, 0x9b, 0xed, 0x4a, - 0xcc, 0x05, 0xf4, 0xe7, 0x06, 0x5c, 0xba, 0x4f, 0x78, 0xb5, 0x48, 0xa3, 0x0f, 0xeb, 0x85, 0x9c, - 0x50, 0xcc, 0x7b, 0x8f, 0xe7, 0x8d, 0xdb, 0x32, 0x5b, 0x73, 0x01, 0x1d, 0xc9, 0x63, 0xe7, 0xf1, - 0x87, 0xde, 0xad, 0x0d, 0xb4, 0xcc, 0xfc, 0x5b, 0x27, 0x6d, 0xa7, 0x47, 0xfd, 0x7c, 0xef, 0x5f, - 0xaf, 0xb6, 0x1a, 0xff, 0x7e, 0xb5, 0xd5, 0xf8, 0xdf, 0xab, 0xad, 0xc6, 0x2f, 0x6e, 0xbf, 0xe6, - 0xe7, 0xb6, 0xc2, 0x2f, 0x78, 0x98, 0x51, 0xc7, 0xa3, 0x24, 0xe0, 0xc7, 0x4b, 0xf2, 0xd6, 0x6e, - 0xff, 0x3f, 0x00, 0x00, 0xff, 0xff, 0x46, 0x3e, 0x2d, 0xff, 0xe0, 0x1b, 0x00, 0x00, + // 2127 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5a, 0x5b, 0x6f, 0x1b, 0xc7, + 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. @@ -2010,8 +2371,14 @@ type RepoServerServiceClient interface { GetAppDetails(ctx context.Context, in *RepoServerAppDetailsQuery, opts ...grpc.CallOption) (*RepoAppDetailsResponse, error) // Get the meta-data (author, date, tags, message) for a specific revision of the repo GetRevisionMetadata(ctx context.Context, in *RepoServerRevisionMetadataRequest, opts ...grpc.CallOption) (*v1alpha1.RevisionMetadata, error) + // Get the chart details (author, date, tags, message) for a specific revision of the repo + GetRevisionChartDetails(ctx context.Context, in *RepoServerRevisionChartDetailsRequest, opts ...grpc.CallOption) (*v1alpha1.ChartDetails, error) // GetHelmCharts returns list of helm charts in the specified repository GetHelmCharts(ctx context.Context, in *HelmChartsRequest, opts ...grpc.CallOption) (*HelmChartsResponse, error) + // GetGitFiles returns a set of file paths and their contents for the given repo + GetGitFiles(ctx context.Context, in *GitFilesRequest, opts ...grpc.CallOption) (*GitFilesResponse, error) + // GetGitDirectories returns a set of directory paths for the given repo + GetGitDirectories(ctx context.Context, in *GitDirectoriesRequest, opts ...grpc.CallOption) (*GitDirectoriesResponse, error) } type repoServerServiceClient struct { @@ -2128,6 +2495,15 @@ func (c *repoServerServiceClient) GetRevisionMetadata(ctx context.Context, in *R return out, nil } +func (c *repoServerServiceClient) GetRevisionChartDetails(ctx context.Context, in *RepoServerRevisionChartDetailsRequest, opts ...grpc.CallOption) (*v1alpha1.ChartDetails, error) { + out := new(v1alpha1.ChartDetails) + err := c.cc.Invoke(ctx, "/repository.RepoServerService/GetRevisionChartDetails", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *repoServerServiceClient) GetHelmCharts(ctx context.Context, in *HelmChartsRequest, opts ...grpc.CallOption) (*HelmChartsResponse, error) { out := new(HelmChartsResponse) err := c.cc.Invoke(ctx, "/repository.RepoServerService/GetHelmCharts", in, out, opts...) @@ -2137,6 +2513,24 @@ func (c *repoServerServiceClient) GetHelmCharts(ctx context.Context, in *HelmCha return out, nil } +func (c *repoServerServiceClient) GetGitFiles(ctx context.Context, in *GitFilesRequest, opts ...grpc.CallOption) (*GitFilesResponse, error) { + out := new(GitFilesResponse) + err := c.cc.Invoke(ctx, "/repository.RepoServerService/GetGitFiles", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *repoServerServiceClient) GetGitDirectories(ctx context.Context, in *GitDirectoriesRequest, opts ...grpc.CallOption) (*GitDirectoriesResponse, error) { + out := new(GitDirectoriesResponse) + err := c.cc.Invoke(ctx, "/repository.RepoServerService/GetGitDirectories", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // RepoServerServiceServer is the server API for RepoServerService service. type RepoServerServiceServer interface { // GenerateManifest generates manifest for application in specified repo name and revision @@ -2157,8 +2551,14 @@ type RepoServerServiceServer interface { GetAppDetails(context.Context, *RepoServerAppDetailsQuery) (*RepoAppDetailsResponse, error) // Get the meta-data (author, date, tags, message) for a specific revision of the repo GetRevisionMetadata(context.Context, *RepoServerRevisionMetadataRequest) (*v1alpha1.RevisionMetadata, error) + // Get the chart details (author, date, tags, message) for a specific revision of the repo + GetRevisionChartDetails(context.Context, *RepoServerRevisionChartDetailsRequest) (*v1alpha1.ChartDetails, error) // GetHelmCharts returns list of helm charts in the specified repository GetHelmCharts(context.Context, *HelmChartsRequest) (*HelmChartsResponse, error) + // GetGitFiles returns a set of file paths and their contents for the given repo + GetGitFiles(context.Context, *GitFilesRequest) (*GitFilesResponse, error) + // GetGitDirectories returns a set of directory paths for the given repo + GetGitDirectories(context.Context, *GitDirectoriesRequest) (*GitDirectoriesResponse, error) } // UnimplementedRepoServerServiceServer can be embedded to have forward compatible implementations. @@ -2192,9 +2592,18 @@ func (*UnimplementedRepoServerServiceServer) GetAppDetails(ctx context.Context, func (*UnimplementedRepoServerServiceServer) GetRevisionMetadata(ctx context.Context, req *RepoServerRevisionMetadataRequest) (*v1alpha1.RevisionMetadata, error) { return nil, status.Errorf(codes.Unimplemented, "method GetRevisionMetadata not implemented") } +func (*UnimplementedRepoServerServiceServer) GetRevisionChartDetails(ctx context.Context, req *RepoServerRevisionChartDetailsRequest) (*v1alpha1.ChartDetails, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRevisionChartDetails not implemented") +} func (*UnimplementedRepoServerServiceServer) GetHelmCharts(ctx context.Context, req *HelmChartsRequest) (*HelmChartsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetHelmCharts not implemented") } +func (*UnimplementedRepoServerServiceServer) GetGitFiles(ctx context.Context, req *GitFilesRequest) (*GitFilesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetGitFiles not implemented") +} +func (*UnimplementedRepoServerServiceServer) GetGitDirectories(ctx context.Context, req *GitDirectoriesRequest) (*GitDirectoriesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetGitDirectories not implemented") +} func RegisterRepoServerServiceServer(s *grpc.Server, srv RepoServerServiceServer) { s.RegisterService(&_RepoServerService_serviceDesc, srv) @@ -2370,6 +2779,24 @@ func _RepoServerService_GetRevisionMetadata_Handler(srv interface{}, ctx context return interceptor(ctx, in, info, handler) } +func _RepoServerService_GetRevisionChartDetails_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RepoServerRevisionChartDetailsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RepoServerServiceServer).GetRevisionChartDetails(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/repository.RepoServerService/GetRevisionChartDetails", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RepoServerServiceServer).GetRevisionChartDetails(ctx, req.(*RepoServerRevisionChartDetailsRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _RepoServerService_GetHelmCharts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(HelmChartsRequest) if err := dec(in); err != nil { @@ -2388,6 +2815,42 @@ func _RepoServerService_GetHelmCharts_Handler(srv interface{}, ctx context.Conte return interceptor(ctx, in, info, handler) } +func _RepoServerService_GetGitFiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GitFilesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RepoServerServiceServer).GetGitFiles(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/repository.RepoServerService/GetGitFiles", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RepoServerServiceServer).GetGitFiles(ctx, req.(*GitFilesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _RepoServerService_GetGitDirectories_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GitDirectoriesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(RepoServerServiceServer).GetGitDirectories(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/repository.RepoServerService/GetGitDirectories", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(RepoServerServiceServer).GetGitDirectories(ctx, req.(*GitDirectoriesRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _RepoServerService_serviceDesc = grpc.ServiceDesc{ ServiceName: "repository.RepoServerService", HandlerType: (*RepoServerServiceServer)(nil), @@ -2424,10 +2887,22 @@ var _RepoServerService_serviceDesc = grpc.ServiceDesc{ MethodName: "GetRevisionMetadata", Handler: _RepoServerService_GetRevisionMetadata_Handler, }, + { + MethodName: "GetRevisionChartDetails", + Handler: _RepoServerService_GetRevisionChartDetails_Handler, + }, { MethodName: "GetHelmCharts", Handler: _RepoServerService_GetHelmCharts_Handler, }, + { + MethodName: "GetGitFiles", + Handler: _RepoServerService_GetGitFiles_Handler, + }, + { + MethodName: "GetGitDirectories", + Handler: _RepoServerService_GetGitDirectories_Handler, + }, }, Streams: []grpc.StreamDesc{ { @@ -2463,6 +2938,26 @@ func (m *ManifestRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.ProjectName) > 0 { + i -= len(m.ProjectName) + copy(dAtA[i:], m.ProjectName) + i = encodeVarintRepository(dAtA, i, uint64(len(m.ProjectName))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xca + } + if len(m.ProjectSourceRepos) > 0 { + for iNdEx := len(m.ProjectSourceRepos) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ProjectSourceRepos[iNdEx]) + copy(dAtA[i:], m.ProjectSourceRepos[iNdEx]) + i = encodeVarintRepository(dAtA, i, uint64(len(m.ProjectSourceRepos[iNdEx]))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xc2 + } + } if len(m.RefSources) > 0 { for k := range m.RefSources { v := m.RefSources[k] @@ -3711,6 +4206,59 @@ func (m *RepoServerRevisionMetadataRequest) MarshalToSizedBuffer(dAtA []byte) (i return len(dAtA) - i, nil } +func (m *RepoServerRevisionChartDetailsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RepoServerRevisionChartDetailsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RepoServerRevisionChartDetailsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Revision) > 0 { + i -= len(m.Revision) + copy(dAtA[i:], m.Revision) + i = encodeVarintRepository(dAtA, i, uint64(len(m.Revision))) + i-- + dAtA[i] = 0x1a + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintRepository(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if m.Repo != nil { + { + size, err := m.Repo.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRepository(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *HelmAppSpec) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4123,98 +4671,331 @@ func (m *HelmChartsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func encodeVarintRepository(dAtA []byte, offset int, v uint64) int { - offset -= sovRepository(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *GitFilesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *ManifestRequest) Size() (n int) { - if m == nil { - return 0 - } + +func (m *GitFilesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GitFilesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.Repo != nil { - l = m.Repo.Size() - n += 1 + l + sovRepository(uint64(l)) - } - l = len(m.Revision) - if l > 0 { - n += 1 + l + sovRepository(uint64(l)) - } - if m.NoCache { - n += 2 - } - l = len(m.AppLabelKey) - if l > 0 { - n += 1 + l + sovRepository(uint64(l)) - } - l = len(m.AppName) - if l > 0 { - n += 1 + l + sovRepository(uint64(l)) - } - l = len(m.Namespace) - if l > 0 { - n += 1 + l + sovRepository(uint64(l)) - } - if m.ApplicationSource != nil { - l = m.ApplicationSource.Size() - n += 1 + l + sovRepository(uint64(l)) + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.Repos) > 0 { - for _, e := range m.Repos { - l = e.Size() - n += 1 + l + sovRepository(uint64(l)) + if m.NoRevisionCache { + i-- + if m.NoRevisionCache { + dAtA[i] = 1 + } else { + dAtA[i] = 0 } + i-- + dAtA[i] = 0x30 } - if len(m.Plugins) > 0 { - for _, e := range m.Plugins { - l = e.Size() - n += 1 + l + sovRepository(uint64(l)) + if m.NewGitFileGlobbingEnabled { + i-- + if m.NewGitFileGlobbingEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 } + i-- + dAtA[i] = 0x28 } - if m.KustomizeOptions != nil { - l = m.KustomizeOptions.Size() - n += 1 + l + sovRepository(uint64(l)) + if len(m.Path) > 0 { + i -= len(m.Path) + copy(dAtA[i:], m.Path) + i = encodeVarintRepository(dAtA, i, uint64(len(m.Path))) + i-- + dAtA[i] = 0x22 } - l = len(m.KubeVersion) - if l > 0 { - n += 1 + l + sovRepository(uint64(l)) + if len(m.Revision) > 0 { + i -= len(m.Revision) + copy(dAtA[i:], m.Revision) + i = encodeVarintRepository(dAtA, i, uint64(len(m.Revision))) + i-- + dAtA[i] = 0x1a } - if len(m.ApiVersions) > 0 { - for _, s := range m.ApiVersions { - l = len(s) - n += 1 + l + sovRepository(uint64(l)) + if m.SubmoduleEnabled { + i-- + if m.SubmoduleEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 } + i-- + dAtA[i] = 0x10 } - if m.VerifySignature { - n += 3 - } - if len(m.HelmRepoCreds) > 0 { - for _, e := range m.HelmRepoCreds { - l = e.Size() - n += 2 + l + sovRepository(uint64(l)) + if m.Repo != nil { + { + size, err := m.Repo.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRepository(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0xa } - if m.NoRevisionCache { - n += 3 + return len(dAtA) - i, nil +} + +func (m *GitFilesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - l = len(m.TrackingMethod) - if l > 0 { - n += 2 + l + sovRepository(uint64(l)) + return dAtA[:n], nil +} + +func (m *GitFilesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GitFilesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) } - if len(m.EnabledSourceTypes) > 0 { - for k, v := range m.EnabledSourceTypes { - _ = k - _ = v - mapEntrySize := 1 + len(k) + sovRepository(uint64(len(k))) + 1 + 1 - n += mapEntrySize + 2 + sovRepository(uint64(mapEntrySize)) + if len(m.Map) > 0 { + for k := range m.Map { + v := m.Map[k] + baseI := i + if len(v) > 0 { + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintRepository(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + } + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintRepository(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintRepository(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *GitDirectoriesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GitDirectoriesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GitDirectoriesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + 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) + i = encodeVarintRepository(dAtA, i, uint64(len(m.Revision))) + i-- + dAtA[i] = 0x1a + } + if m.SubmoduleEnabled { + i-- + if m.SubmoduleEnabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if m.Repo != nil { + { + size, err := m.Repo.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintRepository(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *GitDirectoriesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GitDirectoriesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GitDirectoriesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.Paths) > 0 { + for iNdEx := len(m.Paths) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Paths[iNdEx]) + copy(dAtA[i:], m.Paths[iNdEx]) + i = encodeVarintRepository(dAtA, i, uint64(len(m.Paths[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintRepository(dAtA []byte, offset int, v uint64) int { + offset -= sovRepository(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ManifestRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Repo != nil { + l = m.Repo.Size() + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.Revision) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + if m.NoCache { + n += 2 + } + l = len(m.AppLabelKey) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.AppName) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + if m.ApplicationSource != nil { + l = m.ApplicationSource.Size() + n += 1 + l + sovRepository(uint64(l)) + } + if len(m.Repos) > 0 { + for _, e := range m.Repos { + l = e.Size() + n += 1 + l + sovRepository(uint64(l)) + } + } + if len(m.Plugins) > 0 { + for _, e := range m.Plugins { + l = e.Size() + n += 1 + l + sovRepository(uint64(l)) + } + } + if m.KustomizeOptions != nil { + l = m.KustomizeOptions.Size() + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.KubeVersion) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + if len(m.ApiVersions) > 0 { + for _, s := range m.ApiVersions { + l = len(s) + n += 1 + l + sovRepository(uint64(l)) + } + } + if m.VerifySignature { + n += 3 + } + if len(m.HelmRepoCreds) > 0 { + for _, e := range m.HelmRepoCreds { + l = e.Size() + n += 2 + l + sovRepository(uint64(l)) + } + } + if m.NoRevisionCache { + n += 3 + } + l = len(m.TrackingMethod) + if l > 0 { + n += 2 + l + sovRepository(uint64(l)) + } + if len(m.EnabledSourceTypes) > 0 { + for k, v := range m.EnabledSourceTypes { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovRepository(uint64(len(k))) + 1 + 1 + n += mapEntrySize + 2 + sovRepository(uint64(mapEntrySize)) } } if m.HelmOptions != nil { @@ -4237,6 +5018,16 @@ func (m *ManifestRequest) Size() (n int) { n += mapEntrySize + 2 + sovRepository(uint64(mapEntrySize)) } } + if len(m.ProjectSourceRepos) > 0 { + for _, s := range m.ProjectSourceRepos { + l = len(s) + n += 2 + l + sovRepository(uint64(l)) + } + } + l = len(m.ProjectName) + if l > 0 { + n += 2 + l + sovRepository(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -4688,6 +5479,30 @@ func (m *RepoServerRevisionMetadataRequest) Size() (n int) { return n } +func (m *RepoServerRevisionChartDetailsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Repo != nil { + l = m.Repo.Size() + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.Revision) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *HelmAppSpec) Size() (n int) { if m == nil { return 0 @@ -4883,31 +5698,132 @@ func (m *HelmChartsResponse) Size() (n int) { return n } -func sovRepository(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozRepository(x uint64) (n int) { - return sovRepository(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *ManifestRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRepository - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } +func (m *GitFilesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Repo != nil { + l = m.Repo.Size() + n += 1 + l + sovRepository(uint64(l)) + } + if m.SubmoduleEnabled { + n += 2 + } + l = len(m.Revision) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + l = len(m.Path) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + if m.NewGitFileGlobbingEnabled { + n += 2 + } + if m.NoRevisionCache { + n += 2 + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *GitFilesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Map) > 0 { + for k, v := range m.Map { + _ = k + _ = v + l = 0 + if len(v) > 0 { + l = 1 + len(v) + sovRepository(uint64(len(v))) + } + mapEntrySize := 1 + len(k) + sovRepository(uint64(len(k))) + l + n += mapEntrySize + 1 + sovRepository(uint64(mapEntrySize)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *GitDirectoriesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Repo != nil { + l = m.Repo.Size() + n += 1 + l + sovRepository(uint64(l)) + } + if m.SubmoduleEnabled { + n += 2 + } + l = len(m.Revision) + if l > 0 { + n += 1 + l + sovRepository(uint64(l)) + } + if m.NoRevisionCache { + n += 2 + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *GitDirectoriesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Paths) > 0 { + for _, s := range m.Paths { + l = len(s) + n += 1 + l + sovRepository(uint64(l)) + } + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func sovRepository(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozRepository(x uint64) (n int) { + return sovRepository(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ManifestRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } } fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) @@ -5712,6 +6628,70 @@ func (m *ManifestRequest) Unmarshal(dAtA []byte) error { } m.RefSources[mapkey] = mapvalue iNdEx = postIndex + case 24: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProjectSourceRepos", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + 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 ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProjectSourceRepos = append(m.ProjectSourceRepos, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 25: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProjectName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + 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 ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProjectName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipRepository(dAtA[iNdEx:]) @@ -8473,7 +9453,7 @@ func (m *RepoServerRevisionMetadataRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *HelmAppSpec) Unmarshal(dAtA []byte) error { +func (m *RepoServerRevisionChartDetailsRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -8496,17 +9476,17 @@ func (m *HelmAppSpec) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: HelmAppSpec: wiretype end group for non-group") + return fmt.Errorf("proto: RepoServerRevisionChartDetailsRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: HelmAppSpec: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: RepoServerRevisionChartDetailsRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Repo", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowRepository @@ -8516,27 +9496,31 @@ func (m *HelmAppSpec) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthRepository } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthRepository } if postIndex > l { return io.ErrUnexpectedEOF } - m.Name = string(dAtA[iNdEx:postIndex]) + if m.Repo == nil { + m.Repo = &v1alpha1.Repository{} + } + if err := m.Repo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 3: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ValueFiles", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -8564,45 +9548,11 @@ func (m *HelmAppSpec) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ValueFiles = append(m.ValueFiles, string(dAtA[iNdEx:postIndex])) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Parameters", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRepository - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthRepository - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthRepository - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Parameters = append(m.Parameters, &v1alpha1.HelmParameter{}) - if err := m.Parameters[len(m.Parameters)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Name = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 5: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Values", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Revision", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -8630,21 +9580,202 @@ func (m *HelmAppSpec) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Values = string(dAtA[iNdEx:postIndex]) + m.Revision = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field FileParameters", wireType) + default: + iNdEx = preIndex + skippy, err := skipRepository(dAtA[iNdEx:]) + if err != nil { + return err } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRepository - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRepository + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HelmAppSpec) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: HelmAppSpec: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HelmAppSpec: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + 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 ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValueFiles", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + 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 ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValueFiles = append(m.ValueFiles, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Parameters", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRepository + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Parameters = append(m.Parameters, &v1alpha1.HelmParameter{}) + if err := m.Parameters[len(m.Parameters)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Values", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + 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 ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Values = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FileParameters", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] iNdEx++ msglen |= int(b&0x7F) << shift if b < 0x80 { @@ -9616,6 +10747,638 @@ func (m *HelmChartsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *GitFilesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GitFilesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GitFilesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Repo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRepository + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Repo == nil { + m.Repo = &v1alpha1.Repository{} + } + if err := m.Repo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SubmoduleEnabled", 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.SubmoduleEnabled = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Revision", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + 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 ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Revision = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + 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 ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Path = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NewGitFileGlobbingEnabled", 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.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:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRepository + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GitFilesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GitFilesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GitFilesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Map", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRepository + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Map == nil { + m.Map = make(map[string][]byte) + } + var mapkey string + mapvalue := []byte{} + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthRepository + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthRepository + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var mapbyteLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapbyteLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intMapbyteLen := int(mapbyteLen) + if intMapbyteLen < 0 { + return ErrInvalidLengthRepository + } + postbytesIndex := iNdEx + intMapbyteLen + if postbytesIndex < 0 { + return ErrInvalidLengthRepository + } + if postbytesIndex > l { + return io.ErrUnexpectedEOF + } + mapvalue = make([]byte, mapbyteLen) + copy(mapvalue, dAtA[iNdEx:postbytesIndex]) + iNdEx = postbytesIndex + } else { + iNdEx = entryPreIndex + skippy, err := skipRepository(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRepository + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Map[mapkey] = mapvalue + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRepository(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRepository + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GitDirectoriesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GitDirectoriesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GitDirectoriesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Repo", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthRepository + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Repo == nil { + m.Repo = &v1alpha1.Repository{} + } + if err := m.Repo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SubmoduleEnabled", 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.SubmoduleEnabled = bool(v != 0) + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Revision", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + 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 ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + 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:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRepository + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GitDirectoriesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GitDirectoriesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GitDirectoriesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Paths", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + 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 ErrInvalidLengthRepository + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthRepository + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Paths = append(m.Paths, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipRepository(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthRepository + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipRepository(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/reposerver/cache/cache.go b/reposerver/cache/cache.go index 61b4ff6abd85b..5b15299660ad4 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/go-redis/redis/v8" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -25,11 +24,13 @@ import ( ) var ErrCacheMiss = cacheutil.ErrCacheMiss +var ErrCacheKeyLocked = cacheutil.ErrCacheKeyLocked type Cache struct { - cache *cacheutil.Cache - repoCacheExpiration time.Duration - revisionCacheExpiration time.Duration + cache *cacheutil.Cache + repoCacheExpiration time.Duration + revisionCacheExpiration time.Duration + revisionCacheLockTimeout time.Duration } // ClusterRuntimeInfo holds cluster runtime information @@ -40,25 +41,27 @@ type ClusterRuntimeInfo interface { GetKubeVersion() string } -func NewCache(cache *cacheutil.Cache, repoCacheExpiration time.Duration, revisionCacheExpiration time.Duration) *Cache { - return &Cache{cache, repoCacheExpiration, revisionCacheExpiration} +func NewCache(cache *cacheutil.Cache, repoCacheExpiration time.Duration, revisionCacheExpiration time.Duration, revisionCacheLockTimeout time.Duration) *Cache { + return &Cache{cache, repoCacheExpiration, revisionCacheExpiration, revisionCacheLockTimeout} } -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 + var revisionCacheLockTimeout time.Duration cmd.Flags().DurationVar(&repoCacheExpiration, "repo-cache-expiration", env.ParseDurationFromEnv("ARGOCD_REPO_CACHE_EXPIRATION", 24*time.Hour, 0, math.MaxInt64), "Cache expiration for repo state, incl. app lists, app details, manifest generation, revision meta-data") cmd.Flags().DurationVar(&revisionCacheExpiration, "revision-cache-expiration", env.ParseDurationFromEnv("ARGOCD_RECONCILIATION_TIMEOUT", 3*time.Minute, 0, math.MaxInt64), "Cache expiration for cached revision") + cmd.Flags().DurationVar(&revisionCacheLockTimeout, "revision-cache-lock-timeout", env.ParseDurationFromEnv("ARGOCD_REVISION_CACHE_LOCK_TIMEOUT", 10*time.Second, 0, math.MaxInt64), "Cache TTL for locks to prevent duplicate requests on revisions, set to 0 to disable") repoFactory := cacheutil.AddCacheFlagsToCmd(cmd, opts...) return func() (*Cache, error) { cache, err := repoFactory() if err != nil { - return nil, err + return nil, fmt.Errorf("error adding cache flags to cmd: %w", err) } - return NewCache(cache, repoCacheExpiration, revisionCacheExpiration), nil + return NewCache(cache, repoCacheExpiration, revisionCacheExpiration, revisionCacheLockTimeout), nil } } @@ -88,24 +91,31 @@ func getRefTargetRevisionMappingForCacheKey(refTargetRevisionMapping appv1.RefTa return res } -func appSourceKey(appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping) uint32 { - return hash.FNVa(appSourceKeyJSON(appSrc, srcRefs)) +func appSourceKey(appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, refSourceCommitSHAs ResolvedRevisions) uint32 { + return hash.FNVa(appSourceKeyJSON(appSrc, srcRefs, refSourceCommitSHAs)) } +// ResolvedRevisions is a map of "normalized git URL" -> "git commit SHA". When one source references another source, +// the referenced source revision may change, for example, when someone pushes a commit to the referenced branch. This +// map lets us keep track of the current revision for each referenced source. +type ResolvedRevisions map[string]string + type appSourceKeyStruct struct { - AppSrc *appv1.ApplicationSource `json:"appSrc"` - SrcRefs refTargetRevisionMappingForCacheKey `json:"srcRefs"` + AppSrc *appv1.ApplicationSource `json:"appSrc"` + SrcRefs refTargetRevisionMappingForCacheKey `json:"srcRefs"` + ResolvedRevisions ResolvedRevisions `json:"resolvedRevisions,omitempty"` } -func appSourceKeyJSON(appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping) string { +func appSourceKeyJSON(appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, refSourceCommitSHAs ResolvedRevisions) string { appSrc = appSrc.DeepCopy() if !appSrc.IsHelm() { appSrc.RepoURL = "" // superseded by commitSHA appSrc.TargetRevision = "" // superseded by commitSHA } appSrcStr, _ := json.Marshal(appSourceKeyStruct{ - AppSrc: appSrc, - SrcRefs: getRefTargetRevisionMappingForCacheKey(srcRefs), + AppSrc: appSrc, + SrcRefs: getRefTargetRevisionMappingForCacheKey(srcRefs), + ResolvedRevisions: refSourceCommitSHAs, }) return string(appSrcStr) } @@ -139,7 +149,12 @@ func (c *Cache) ListApps(repoUrl, revision string) (map[string]string, error) { } func (c *Cache) SetApps(repoUrl, revision string, apps map[string]string) error { - return c.cache.SetItem(listApps(repoUrl, revision), apps, c.repoCacheExpiration, apps == nil) + return c.cache.SetItem( + listApps(repoUrl, revision), + apps, + &cacheutil.CacheActionOpts{ + Expiration: c.repoCacheExpiration, + Delete: apps == nil}) } func helmIndexRefsKey(repo string) string { @@ -148,7 +163,14 @@ func helmIndexRefsKey(repo string) string { // SetHelmIndex stores helm repository index.yaml content to cache func (c *Cache) SetHelmIndex(repo string, indexData []byte) error { - return c.cache.SetItem(helmIndexRefsKey(repo), indexData, c.revisionCacheExpiration, false) + if indexData == nil { + // Logged as warning upstream + return fmt.Errorf("helm index data is nil, skipping cache") + } + return c.cache.SetItem( + helmIndexRefsKey(repo), + indexData, + &cacheutil.CacheActionOpts{Expiration: c.revisionCacheExpiration}) } // GetHelmIndex retrieves helm repository index.yaml content from cache @@ -166,26 +188,110 @@ func (c *Cache) SetGitReferences(repo string, references []*plumbing.Reference) for i := range references { input = append(input, references[i].Strings()) } - return c.cache.SetItem(gitRefsKey(repo), input, c.revisionCacheExpiration, false) + return c.cache.SetItem(gitRefsKey(repo), input, &cacheutil.CacheActionOpts{Expiration: c.revisionCacheExpiration}) } -// GetGitReferences retrieves resolved Git repository references from cache -func (c *Cache) GetGitReferences(repo string, references *[]*plumbing.Reference) error { +// Converts raw cache items to plumbing.Reference objects +func GitRefCacheItemToReferences(cacheItem [][2]string) *[]*plumbing.Reference { + var res []*plumbing.Reference + for i := range cacheItem { + // Skip empty data + if cacheItem[i][0] != "" || cacheItem[i][1] != "" { + res = append(res, plumbing.NewReferenceFromStrings(cacheItem[i][0], cacheItem[i][1])) + } + } + return &res +} + +// TryLockGitRefCache attempts to lock the key for the Git repository references if the key doesn't exist, returns the value of +// GetGitReferences after calling the SET +func (c *Cache) TryLockGitRefCache(repo string, lockId string, references *[]*plumbing.Reference) (string, error) { + // This try set with DisableOverwrite is important for making sure that only one process is able to claim ownership + // A normal get + set, or just set would cause ownership to go to whoever the last writer was, and during race conditions + // leads to duplicate requests + err := c.cache.SetItem(gitRefsKey(repo), [][2]string{{cacheutil.CacheLockedValue, lockId}}, &cacheutil.CacheActionOpts{ + Expiration: c.revisionCacheLockTimeout, + DisableOverwrite: true}) + if err != nil { + // Log but ignore this error since we'll want to retry, failing to obtain the lock should not throw an error + log.Errorf("Error attempting to acquire git references cache lock: %v", err) + } + return c.GetGitReferences(repo, references) +} + +// Retrieves the cache item for git repo references. Returns foundLockId, error +func (c *Cache) GetGitReferences(repo string, references *[]*plumbing.Reference) (string, error) { var input [][2]string - if err := c.cache.GetItem(gitRefsKey(repo), &input); err != nil { - return err + err := c.cache.GetItem(gitRefsKey(repo), &input) + valueExists := len(input) > 0 && len(input[0]) > 0 + switch { + // Unexpected Error + case err != nil && err != ErrCacheMiss: + log.Errorf("Error attempting to retrieve git references from cache: %v", err) + return "", err + // Value is set + case valueExists && input[0][0] != cacheutil.CacheLockedValue: + *references = *GitRefCacheItemToReferences(input) + return "", nil + // Key is locked + case valueExists: + return input[0][1], nil + // No key or empty key + default: + return "", nil } - var res []*plumbing.Reference - for i := range input { - res = append(res, plumbing.NewReferenceFromStrings(input[i][0], input[i][1])) +} + +// GetOrLockGitReferences retrieves the git references if they exist, otherwise creates a lock and returns so the caller can populate the cache +// Returns isLockOwner, localLockId, error +func (c *Cache) GetOrLockGitReferences(repo string, lockId string, references *[]*plumbing.Reference) (string, error) { + // Value matches the ttl on the lock in TryLockGitRefCache + waitUntil := time.Now().Add(c.revisionCacheLockTimeout) + // Wait only the maximum amount of time configured for the lock + // if the configured time is zero then the for loop will never run and instead act as the owner immediately + for time.Now().Before(waitUntil) { + // Get current cache state + if foundLockId, err := c.GetGitReferences(repo, references); foundLockId == lockId || err != nil || (references != nil && len(*references) > 0) { + return foundLockId, err + } + if foundLockId, err := c.TryLockGitRefCache(repo, lockId, references); foundLockId == lockId || err != nil || (references != nil && len(*references) > 0) { + return foundLockId, err + } + time.Sleep(1 * time.Second) } - *references = res - return nil + // If configured time is 0 then this is expected + if c.revisionCacheLockTimeout > 0 { + log.Debug("Repository cache was unable to acquire lock or valid data within timeout") + } + // Timeout waiting for lock + return lockId, nil +} + +// UnlockGitReferences unlocks the key for the Git repository references if needed +func (c *Cache) UnlockGitReferences(repo string, lockId string) error { + var input [][2]string + var err error + if err = c.cache.GetItem(gitRefsKey(repo), &input); err == nil && + input != nil && + len(input) > 0 && + len(input[0]) > 1 && + input[0][0] == cacheutil.CacheLockedValue && + input[0][1] == lockId { + // We have the lock, so remove it + return c.cache.SetItem(gitRefsKey(repo), input, &cacheutil.CacheActionOpts{Delete: true}) + } + return err } -func manifestCacheKey(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, namespace string, trackingMethod string, appLabelKey string, appName string, info ClusterRuntimeInfo) string { +// refSourceCommitSHAs is a list of resolved revisions for each ref source. This allows us to invalidate the cache +// when someone pushes a commit to a source which is referenced from the main source (the one referred to by `revision`). +func manifestCacheKey(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, namespace string, trackingMethod string, appLabelKey string, appName string, info ClusterRuntimeInfo, refSourceCommitSHAs ResolvedRevisions) string { + // TODO: this function is getting unwieldy. We should probably consolidate some of this stuff into a struct. For + // example, revision could be part of ResolvedRevisions. And srcRefs is probably redundant now that + // refSourceCommitSHAs has been added. We don't need to know the _target_ revisions of the referenced sources + // when the _resolved_ revisions are already part of the key. trackingKey := trackingKey(appLabelKey, trackingMethod) - return fmt.Sprintf("mfst|%s|%s|%s|%s|%d", trackingKey, appName, revision, namespace, appSourceKey(appSrc, srcRefs)+clusterRuntimeInfoKey(info)) + return fmt.Sprintf("mfst|%s|%s|%s|%s|%d", trackingKey, appName, revision, namespace, appSourceKey(appSrc, srcRefs, refSourceCommitSHAs)+clusterRuntimeInfoKey(info)) } func trackingKey(appLabelKey string, trackingMethod string) string { @@ -198,11 +304,11 @@ func trackingKey(appLabelKey string, trackingMethod string) string { // LogDebugManifestCacheKeyFields logs all the information included in a manifest cache key. It's intended to be run // before every manifest cache operation to help debug cache misses. -func LogDebugManifestCacheKeyFields(message string, reason string, revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, clusterInfo ClusterRuntimeInfo, namespace string, trackingMethod string, appLabelKey string, appName string) { +func LogDebugManifestCacheKeyFields(message string, reason string, revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, clusterInfo ClusterRuntimeInfo, namespace string, trackingMethod string, appLabelKey string, appName string, refSourceCommitSHAs ResolvedRevisions) { if log.IsLevelEnabled(log.DebugLevel) { log.WithFields(log.Fields{ "revision": revision, - "appSrc": appSourceKeyJSON(appSrc, srcRefs), + "appSrc": appSourceKeyJSON(appSrc, srcRefs, refSourceCommitSHAs), "namespace": namespace, "trackingKey": trackingKey(appLabelKey, trackingMethod), "appName": appName, @@ -212,8 +318,14 @@ func LogDebugManifestCacheKeyFields(message string, reason string, revision stri } } -func (c *Cache) GetManifests(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, clusterInfo ClusterRuntimeInfo, namespace string, trackingMethod string, appLabelKey string, appName string, res *CachedManifestResponse) error { - err := c.cache.GetItem(manifestCacheKey(revision, appSrc, srcRefs, namespace, trackingMethod, appLabelKey, appName, clusterInfo), res) +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) if err != nil { return err @@ -228,9 +340,9 @@ func (c *Cache) GetManifests(revision string, appSrc *appv1.ApplicationSource, s if hash != res.CacheEntryHash || res.ManifestResponse == nil && res.MostRecentError == "" { log.Warnf("Manifest hash did not match expected value or cached manifests response is empty, treating as a cache miss: %s", appName) - LogDebugManifestCacheKeyFields("deleting manifests cache", "manifest hash did not match or cached response is empty", revision, appSrc, srcRefs, clusterInfo, namespace, trackingMethod, appLabelKey, appName) + LogDebugManifestCacheKeyFields("deleting manifests cache", "manifest hash did not match or cached response is empty", revision, appSrc, srcRefs, clusterInfo, namespace, trackingMethod, appLabelKey, appName, refSourceCommitSHAs) - err = c.DeleteManifests(revision, appSrc, srcRefs, clusterInfo, namespace, trackingMethod, appLabelKey, appName) + err = c.DeleteManifests(revision, appSrc, srcRefs, clusterInfo, namespace, trackingMethod, appLabelKey, appName, refSourceCommitSHAs) if err != nil { return fmt.Errorf("Unable to delete manifest after hash mismatch, %v", err) } @@ -245,7 +357,7 @@ func (c *Cache) GetManifests(revision string, appSrc *appv1.ApplicationSource, s return nil } -func (c *Cache) SetManifests(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, clusterInfo ClusterRuntimeInfo, namespace string, trackingMethod string, appLabelKey string, appName string, res *CachedManifestResponse) error { +func (c *Cache) SetManifests(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, clusterInfo ClusterRuntimeInfo, namespace string, trackingMethod string, appLabelKey string, appName string, res *CachedManifestResponse, refSourceCommitSHAs ResolvedRevisions) error { // Generate and apply the cache entry hash, before writing if res != nil { res = res.shallowCopy() @@ -256,26 +368,39 @@ func (c *Cache) SetManifests(revision string, appSrc *appv1.ApplicationSource, s res.CacheEntryHash = hash } - return c.cache.SetItem(manifestCacheKey(revision, appSrc, srcRefs, namespace, trackingMethod, appLabelKey, appName, clusterInfo), res, c.repoCacheExpiration, res == nil) + return c.cache.SetItem( + manifestCacheKey(revision, appSrc, srcRefs, namespace, trackingMethod, appLabelKey, appName, clusterInfo, refSourceCommitSHAs), + res, + &cacheutil.CacheActionOpts{ + Expiration: c.repoCacheExpiration, + Delete: res == nil}) } -func (c *Cache) DeleteManifests(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, clusterInfo ClusterRuntimeInfo, namespace, trackingMethod, appLabelKey, appName string) error { - return c.cache.SetItem(manifestCacheKey(revision, appSrc, srcRefs, namespace, trackingMethod, appLabelKey, appName, clusterInfo), "", c.repoCacheExpiration, true) +func (c *Cache) DeleteManifests(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, clusterInfo ClusterRuntimeInfo, namespace, trackingMethod, appLabelKey, appName string, refSourceCommitSHAs ResolvedRevisions) error { + return c.cache.SetItem( + manifestCacheKey(revision, appSrc, srcRefs, namespace, trackingMethod, appLabelKey, appName, clusterInfo, refSourceCommitSHAs), + "", + &cacheutil.CacheActionOpts{Delete: true}) } -func appDetailsCacheKey(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, trackingMethod appv1.TrackingMethod) string { +func appDetailsCacheKey(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, trackingMethod appv1.TrackingMethod, refSourceCommitSHAs ResolvedRevisions) string { if trackingMethod == "" { trackingMethod = argo.TrackingMethodLabel } - return fmt.Sprintf("appdetails|%s|%d|%s", revision, appSourceKey(appSrc, srcRefs), trackingMethod) + return fmt.Sprintf("appdetails|%s|%d|%s", revision, appSourceKey(appSrc, srcRefs, refSourceCommitSHAs), trackingMethod) } -func (c *Cache) GetAppDetails(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, res *apiclient.RepoAppDetailsResponse, trackingMethod appv1.TrackingMethod) error { - return c.cache.GetItem(appDetailsCacheKey(revision, appSrc, srcRefs, trackingMethod), res) +func (c *Cache) GetAppDetails(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, res *apiclient.RepoAppDetailsResponse, trackingMethod appv1.TrackingMethod, refSourceCommitSHAs ResolvedRevisions) error { + return c.cache.GetItem(appDetailsCacheKey(revision, appSrc, srcRefs, trackingMethod, refSourceCommitSHAs), res) } -func (c *Cache) SetAppDetails(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, res *apiclient.RepoAppDetailsResponse, trackingMethod appv1.TrackingMethod) error { - return c.cache.SetItem(appDetailsCacheKey(revision, appSrc, srcRefs, trackingMethod), res, c.repoCacheExpiration, res == nil) +func (c *Cache) SetAppDetails(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, res *apiclient.RepoAppDetailsResponse, trackingMethod appv1.TrackingMethod, refSourceCommitSHAs ResolvedRevisions) error { + return c.cache.SetItem( + appDetailsCacheKey(revision, appSrc, srcRefs, trackingMethod, refSourceCommitSHAs), + res, + &cacheutil.CacheActionOpts{ + Expiration: c.repoCacheExpiration, + Delete: res == nil}) } func revisionMetadataKey(repoURL, revision string) string { @@ -288,7 +413,58 @@ func (c *Cache) GetRevisionMetadata(repoURL, revision string) (*appv1.RevisionMe } func (c *Cache) SetRevisionMetadata(repoURL, revision string, item *appv1.RevisionMetadata) error { - return c.cache.SetItem(revisionMetadataKey(repoURL, revision), item, c.repoCacheExpiration, false) + return c.cache.SetItem( + revisionMetadataKey(repoURL, revision), + item, + &cacheutil.CacheActionOpts{Expiration: c.repoCacheExpiration}) +} + +func revisionChartDetailsKey(repoURL, chart, revision string) string { + return fmt.Sprintf("chartdetails|%s|%s|%s", repoURL, chart, revision) +} + +func (c *Cache) GetRevisionChartDetails(repoURL, chart, revision string) (*appv1.ChartDetails, error) { + item := &appv1.ChartDetails{} + return item, c.cache.GetItem(revisionChartDetailsKey(repoURL, chart, revision), item) +} + +func (c *Cache) SetRevisionChartDetails(repoURL, chart, revision string, item *appv1.ChartDetails) error { + return c.cache.SetItem( + revisionChartDetailsKey(repoURL, chart, revision), + item, + &cacheutil.CacheActionOpts{Expiration: c.repoCacheExpiration}) +} + +func gitFilesKey(repoURL, revision, pattern string) string { + return fmt.Sprintf("gitfiles|%s|%s|%s", repoURL, revision, pattern) +} + +func (c *Cache) SetGitFiles(repoURL, revision, pattern string, files map[string][]byte) error { + return c.cache.SetItem( + gitFilesKey(repoURL, revision, pattern), + &files, + &cacheutil.CacheActionOpts{Expiration: c.repoCacheExpiration}) +} + +func (c *Cache) GetGitFiles(repoURL, revision, pattern string) (map[string][]byte, error) { + var item map[string][]byte + return item, c.cache.GetItem(gitFilesKey(repoURL, revision, pattern), &item) +} + +func gitDirectoriesKey(repoURL, revision string) string { + return fmt.Sprintf("gitdirs|%s|%s", repoURL, revision) +} + +func (c *Cache) SetGitDirectories(repoURL, revision string, directories []string) error { + return c.cache.SetItem( + gitDirectoriesKey(repoURL, revision), + &directories, + &cacheutil.CacheActionOpts{Expiration: c.repoCacheExpiration}) +} + +func (c *Cache) GetGitDirectories(repoURL, revision string) ([]string, error) { + var item []string + return item, c.cache.GetItem(gitDirectoriesKey(repoURL, revision), &item) } func (cmr *CachedManifestResponse) shallowCopy() *CachedManifestResponse { diff --git a/reposerver/cache/cache_test.go b/reposerver/cache/cache_test.go index 747962c5ccaf3..452a9f6e14edb 100644 --- a/reposerver/cache/cache_test.go +++ b/reposerver/cache/cache_test.go @@ -3,36 +3,48 @@ package cache import ( "encoding/json" "errors" + "fmt" "strings" "testing" "time" - "github.com/spf13/cobra" - "github.com/stretchr/testify/assert" - . "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" appv1 "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/mocks" cacheutil "github.com/argoproj/argo-cd/v2/util/cache" + "github.com/go-git/go-git/v5/plumbing" + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) -type fixtures struct { +type MockedCache struct { + mock.Mock *Cache } +type fixtures struct { + mockCache *mocks.MockRepoCache + cache *MockedCache +} + func newFixtures() *fixtures { - return &fixtures{NewCache( - cacheutil.NewCache(cacheutil.NewInMemoryCache(1*time.Hour)), - 1*time.Minute, - 1*time.Minute, - )} + mockCache := mocks.NewMockRepoCache(&mocks.MockCacheOptions{RevisionCacheExpiration: 1 * time.Minute, RepoCacheExpiration: 1 * time.Minute}) + newBaseCache := cacheutil.NewCache(mockCache.RedisClient) + baseCache := NewCache(newBaseCache, 1*time.Minute, 1*time.Minute, 10*time.Second) + return &fixtures{mockCache: mockCache, cache: &MockedCache{Cache: baseCache}} } func TestCache_GetRevisionMetadata(t *testing.T) { - cache := newFixtures().Cache + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + mockCache := fixtures.mockCache // cache miss _, err := cache.GetRevisionMetadata("my-repo-url", "my-revision") assert.Equal(t, ErrCacheMiss, err) + mockCache.RedisClient.AssertCalled(t, "Get", mock.Anything, mock.Anything) // populate cache err = cache.SetRevisionMetadata("my-repo-url", "my-revision", &RevisionMetadata{Message: "my-message"}) assert.NoError(t, err) @@ -46,10 +58,14 @@ func TestCache_GetRevisionMetadata(t *testing.T) { value, err := cache.GetRevisionMetadata("my-repo-url", "my-revision") assert.NoError(t, err) assert.Equal(t, &RevisionMetadata{Message: "my-message"}, value) + mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 1, ExternalGets: 4}) } func TestCache_ListApps(t *testing.T) { - cache := newFixtures().Cache + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + mockCache := fixtures.mockCache // cache miss _, err := cache.ListApps("my-repo-url", "my-revision") assert.Equal(t, ErrCacheMiss, err) @@ -66,66 +82,79 @@ func TestCache_ListApps(t *testing.T) { value, err := cache.ListApps("my-repo-url", "my-revision") assert.NoError(t, err) assert.Equal(t, map[string]string{"foo": "bar"}, value) + mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 1, ExternalGets: 4}) } func TestCache_GetManifests(t *testing.T) { - cache := newFixtures().Cache + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + mockCache := fixtures.mockCache // cache miss q := &apiclient.ManifestRequest{} value := &CachedManifestResponse{} - err := cache.GetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "my-app-label-value", value) + err := cache.GetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "my-app-label-value", value, nil) assert.Equal(t, ErrCacheMiss, err) // populate cache res := &CachedManifestResponse{ManifestResponse: &apiclient.ManifestResponse{SourceType: "my-source-type"}} - err = cache.SetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "my-app-label-value", res) + err = cache.SetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "my-app-label-value", res, nil) assert.NoError(t, err) t.Run("expect cache miss because of changed revision", func(t *testing.T) { - err = cache.GetManifests("other-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "my-app-label-value", value) + err = cache.GetManifests("other-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "my-app-label-value", value, nil) assert.Equal(t, ErrCacheMiss, err) }) t.Run("expect cache miss because of changed path", func(t *testing.T) { - err = cache.GetManifests("my-revision", &ApplicationSource{Path: "other-path"}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "my-app-label-value", value) + err = cache.GetManifests("my-revision", &ApplicationSource{Path: "other-path"}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "my-app-label-value", value, nil) assert.Equal(t, ErrCacheMiss, err) }) t.Run("expect cache miss because of changed namespace", func(t *testing.T) { - err = cache.GetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "other-namespace", "", "my-app-label-key", "my-app-label-value", value) + err = cache.GetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "other-namespace", "", "my-app-label-key", "my-app-label-value", value, nil) assert.Equal(t, ErrCacheMiss, err) }) t.Run("expect cache miss because of changed app label key", func(t *testing.T) { - err = cache.GetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "other-app-label-key", "my-app-label-value", value) + err = cache.GetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "other-app-label-key", "my-app-label-value", value, nil) assert.Equal(t, ErrCacheMiss, err) }) t.Run("expect cache miss because of changed app label value", func(t *testing.T) { - err = cache.GetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "other-app-label-value", value) + err = cache.GetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "other-app-label-value", value, nil) + assert.Equal(t, ErrCacheMiss, err) + }) + t.Run("expect cache miss because of changed referenced source", func(t *testing.T) { + err = cache.GetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "other-app-label-value", value, map[string]string{"my-referenced-source": "my-referenced-revision"}) assert.Equal(t, ErrCacheMiss, err) }) t.Run("expect cache hit", func(t *testing.T) { - err = cache.GetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "my-app-label-value", value) + err = cache.GetManifests("my-revision", &ApplicationSource{}, q.RefSources, q, "my-namespace", "", "my-app-label-key", "my-app-label-value", value, nil) assert.NoError(t, err) assert.Equal(t, &CachedManifestResponse{ManifestResponse: &apiclient.ManifestResponse{SourceType: "my-source-type"}}, value) }) + mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 1, ExternalGets: 8}) } func TestCache_GetAppDetails(t *testing.T) { - cache := newFixtures().Cache + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + mockCache := fixtures.mockCache // cache miss value := &apiclient.RepoAppDetailsResponse{} - emptyRefSources := map[string]*appv1.RefTarget{} - err := cache.GetAppDetails("my-revision", &ApplicationSource{}, emptyRefSources, value, "") + emptyRefSources := map[string]*RefTarget{} + err := cache.GetAppDetails("my-revision", &ApplicationSource{}, emptyRefSources, value, "", nil) assert.Equal(t, ErrCacheMiss, err) res := &apiclient.RepoAppDetailsResponse{Type: "my-type"} - err = cache.SetAppDetails("my-revision", &ApplicationSource{}, emptyRefSources, res, "") + err = cache.SetAppDetails("my-revision", &ApplicationSource{}, emptyRefSources, res, "", nil) assert.NoError(t, err) //cache miss - err = cache.GetAppDetails("other-revision", &ApplicationSource{}, emptyRefSources, value, "") + err = cache.GetAppDetails("other-revision", &ApplicationSource{}, emptyRefSources, value, "", nil) assert.Equal(t, ErrCacheMiss, err) //cache miss - err = cache.GetAppDetails("my-revision", &ApplicationSource{Path: "other-path"}, emptyRefSources, value, "") + err = cache.GetAppDetails("my-revision", &ApplicationSource{Path: "other-path"}, emptyRefSources, value, "", nil) assert.Equal(t, ErrCacheMiss, err) // cache hit - err = cache.GetAppDetails("my-revision", &ApplicationSource{}, emptyRefSources, value, "") + err = cache.GetAppDetails("my-revision", &ApplicationSource{}, emptyRefSources, value, "", nil) assert.NoError(t, err) assert.Equal(t, &apiclient.RepoAppDetailsResponse{Type: "my-type"}, value) + mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 1, ExternalGets: 4}) } func TestAddCacheFlagsToCmd(t *testing.T) { @@ -142,6 +171,7 @@ func TestCachedManifestResponse_HashBehavior(t *testing.T) { cacheutil.NewCache(inMemCache), 1*time.Minute, 1*time.Minute, + 10*time.Second, ) response := apiclient.ManifestResponse{ @@ -149,7 +179,7 @@ func TestCachedManifestResponse_HashBehavior(t *testing.T) { Revision: "revision", Manifests: []string{"sample-text"}, } - appSrc := &appv1.ApplicationSource{} + appSrc := &ApplicationSource{} appKey := "key" appValue := "value" @@ -162,7 +192,7 @@ func TestCachedManifestResponse_HashBehavior(t *testing.T) { NumberOfConsecutiveFailures: 0, } q := &apiclient.ManifestRequest{} - err := repoCache.SetManifests(response.Revision, appSrc, q.RefSources, q, response.Namespace, "", appKey, appValue, store) + err := repoCache.SetManifests(response.Revision, appSrc, q.RefSources, q, response.Namespace, "", appKey, appValue, store, nil) if err != nil { t.Fatal(err) } @@ -193,7 +223,7 @@ func TestCachedManifestResponse_HashBehavior(t *testing.T) { // Retrieve the value using 'GetManifests' and confirm it works retrievedVal := &CachedManifestResponse{} - err = repoCache.GetManifests(response.Revision, appSrc, q.RefSources, q, response.Namespace, "", appKey, appValue, retrievedVal) + err = repoCache.GetManifests(response.Revision, appSrc, q.RefSources, q, response.Namespace, "", appKey, appValue, retrievedVal, nil) if err != nil { t.Fatal(err) } @@ -216,7 +246,7 @@ func TestCachedManifestResponse_HashBehavior(t *testing.T) { // Retrieve the value using GetManifests and confirm it returns a cache miss retrievedVal = &CachedManifestResponse{} - err = repoCache.GetManifests(response.Revision, appSrc, q.RefSources, q, response.Namespace, "", appKey, appValue, retrievedVal) + err = repoCache.GetManifests(response.Revision, appSrc, q.RefSources, q, response.Namespace, "", appKey, appValue, retrievedVal, nil) assert.True(t, err == cacheutil.ErrCacheMiss) @@ -306,3 +336,431 @@ func TestCachedManifestResponse_ShallowCopyExpectedFields(t *testing.T) { } } + +func TestGetGitReferences(t *testing.T) { + t.Run("Valid args, nothing in cache, in-memory only", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + var references []*plumbing.Reference + lockOwner, err := cache.GetGitReferences("test-repo", &references) + assert.NoError(t, err, "Error is cache miss handled inside function") + assert.Equal(t, "", lockOwner, "Lock owner should be empty") + assert.Nil(t, references) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1}) + }) + + t.Run("Valid args, nothing in cache, external only", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + var references []*plumbing.Reference + lockOwner, err := cache.GetGitReferences("test-repo", &references) + assert.NoError(t, err, "Error is cache miss handled inside function") + assert.Equal(t, "", lockOwner, "Lock owner should be empty") + assert.Nil(t, references) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1}) + }) + + t.Run("Valid args, value in cache, in-memory only", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + err := cache.SetGitReferences("test-repo", *GitRefCacheItemToReferences([][2]string{{"test-repo", "ref: test"}})) + assert.NoError(t, err) + var references []*plumbing.Reference + lockOwner, err := cache.GetGitReferences("test-repo", &references) + assert.NoError(t, err) + assert.Equal(t, "", lockOwner, "Lock owner should be empty") + assert.Equal(t, 1, len(references)) + assert.Equal(t, "test", (references)[0].Target().String()) + assert.Equal(t, "test-repo", (references)[0].Name().String()) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 1, ExternalGets: 1}) + }) + + t.Run("cache error", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + fixtures.mockCache.RedisClient.On("Get", mock.Anything, mock.Anything).Unset() + fixtures.mockCache.RedisClient.On("Get", mock.Anything, mock.Anything).Return(errors.New("test cache error")) + var references []*plumbing.Reference + lockOwner, err := cache.GetGitReferences("test-repo", &references) + assert.ErrorContains(t, err, "test cache error", "Error should be propagated") + assert.Equal(t, "", lockOwner, "Lock owner should be empty") + assert.Nil(t, references) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1}) + }) + +} + +func TestGitRefCacheItemToReferences_DataChecks(t *testing.T) { + references := *GitRefCacheItemToReferences(nil) + assert.Equal(t, 0, len(references), "No data should be handled gracefully by returning an empty slice") + references = *GitRefCacheItemToReferences([][2]string{{"", ""}}) + assert.Equal(t, 0, len(references), "Empty data should be discarded") + references = *GitRefCacheItemToReferences([][2]string{{"test", ""}}) + assert.Equal(t, 1, len(references), "Just the key being set should not be discarded") + assert.Equal(t, "test", references[0].Name().String(), "Name should be set and equal test") + references = *GitRefCacheItemToReferences([][2]string{{"", "ref: test1"}}) + assert.Equal(t, 1, len(references), "Just the value being set should not be discarded") + assert.Equal(t, "test1", references[0].Target().String(), "Target should be set and equal test1") + references = *GitRefCacheItemToReferences([][2]string{{"test2", "ref: test2"}}) + assert.Equal(t, 1, len(references), "Valid data is should be preserved") + assert.Equal(t, "test2", references[0].Name().String(), "Name should be set and equal test2") + assert.Equal(t, "test2", references[0].Target().String(), "Target should be set and equal test2") + references = *GitRefCacheItemToReferences([][2]string{{"test3", "ref: test3"}, {"test4", "ref: test4"}}) + assert.Equal(t, 2, len(references), "Valid data is should be preserved") + assert.Equal(t, "test3", references[0].Name().String(), "Name should be set and equal test3") + assert.Equal(t, "test3", references[0].Target().String(), "Target should be set and equal test3") + assert.Equal(t, "test4", references[1].Name().String(), "Name should be set and equal test4") + assert.Equal(t, "test4", references[1].Target().String(), "Target should be set and equal test4") +} + +func TestTryLockGitRefCache_OwnershipFlows(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + utilCache := cache.cache + var references []*plumbing.Reference + // Test setting the lock + _, err := cache.TryLockGitRefCache("my-repo-url", "my-lock-id", &references) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 1, ExternalGets: 1}) + assert.NoError(t, err) + var output [][2]string + key := fmt.Sprintf("git-refs|%s", "my-repo-url") + err = utilCache.GetItem(key, &output) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 1, ExternalGets: 2}) + assert.NoError(t, err) + assert.Equal(t, "locked", output[0][0], "The lock should be set") + assert.Equal(t, "my-lock-id", output[0][1], "The lock should be set to the provided lock id") + // Test not being able to overwrite the lock + _, err = cache.TryLockGitRefCache("my-repo-url", "other-lock-id", &references) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 2, ExternalGets: 3}) + assert.NoError(t, err) + err = utilCache.GetItem(key, &output) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 2, ExternalGets: 4}) + assert.NoError(t, err) + assert.Equal(t, "locked", output[0][0], "The lock should not have changed") + assert.Equal(t, "my-lock-id", output[0][1], "The lock should not have changed") + // Test can overwrite once there is nothing set + err = utilCache.SetItem(key, [][2]string{}, &cacheutil.CacheActionOpts{Expiration: 0, Delete: true}) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 2, ExternalGets: 4, ExternalDeletes: 1}) + assert.NoError(t, err) + _, err = cache.TryLockGitRefCache("my-repo-url", "other-lock-id", &references) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 3, ExternalGets: 5, ExternalDeletes: 1}) + assert.NoError(t, err) + err = utilCache.GetItem(key, &output) + assert.NoError(t, err) + assert.Equal(t, "locked", output[0][0], "The lock should be set") + assert.Equal(t, "other-lock-id", output[0][1], "The lock id should have changed to other-lock-id") + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 3, ExternalGets: 6, ExternalDeletes: 1}) +} + +func TestGetOrLockGitReferences(t *testing.T) { + t.Run("Test cache lock get lock", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + var references []*plumbing.Reference + lockId, err := cache.GetOrLockGitReferences("test-repo", "test-lock-id", &references) + assert.NoError(t, err) + assert.Equal(t, lockId, "test-lock-id") + assert.NotEqual(t, "", lockId, "Lock id should be set") + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 1, ExternalGets: 2}) + }) + + t.Run("Test cache lock, cache hit local", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + err := cache.SetGitReferences("test-repo", *GitRefCacheItemToReferences([][2]string{{"test-repo", "ref: test"}})) + assert.NoError(t, err) + var references []*plumbing.Reference + lockId, err := cache.GetOrLockGitReferences("test-repo", "test-lock-id", &references) + assert.NoError(t, err) + assert.NotEqual(t, lockId, "test-lock-id") + assert.Equal(t, "", lockId, "Lock id should not be set") + assert.Equal(t, "test-repo", references[0].Name().String()) + assert.Equal(t, "test", references[0].Target().String()) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 1, ExternalGets: 1}) + }) + + t.Run("Test cache lock, cache hit remote", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + err := fixtures.cache.cache.SetItem( + "git-refs|test-repo", + [][2]string{{"test-repo", "ref: test"}}, + &cacheutil.CacheActionOpts{ + Expiration: 30 * time.Second}) + assert.NoError(t, err) + var references []*plumbing.Reference + lockId, err := cache.GetOrLockGitReferences("test-repo", "test-lock-id", &references) + assert.NoError(t, err) + assert.NotEqual(t, lockId, "test-lock-id") + assert.Equal(t, "", lockId, "Lock id should not be set") + assert.Equal(t, "test-repo", references[0].Name().String()) + assert.Equal(t, "test", references[0].Target().String()) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 1, ExternalGets: 1}) + }) + + t.Run("Test miss, populated by external", func(t *testing.T) { + // Tests the case where another process populates the external cache when trying + // to obtain the lock + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + fixtures.mockCache.RedisClient.On("Get", mock.Anything, mock.Anything).Unset() + fixtures.mockCache.RedisClient.On("Get", mock.Anything, mock.Anything).Return(cacheutil.ErrCacheMiss).Once().Run(func(args mock.Arguments) { + err := cache.SetGitReferences("test-repo", *GitRefCacheItemToReferences([][2]string{{"test-repo", "ref: test"}})) + assert.NoError(t, err) + }).On("Get", mock.Anything, mock.Anything).Return(nil) + var references []*plumbing.Reference + lockId, err := cache.GetOrLockGitReferences("test-repo", "test-lock-id", &references) + assert.NoError(t, err) + assert.NotEqual(t, lockId, "test-lock-id") + assert.Equal(t, "", lockId, "Lock id should not be set") + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 2, ExternalGets: 2}) + }) + + t.Run("Test cache lock timeout", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + // Create conditions for cache hit, which would result in false on updateCache if we weren't reaching the timeout + err := cache.SetGitReferences("test-repo", *GitRefCacheItemToReferences([][2]string{{"test-repo", "ref: test"}})) + assert.NoError(t, err) + cache.revisionCacheLockTimeout = -1 * time.Second + var references []*plumbing.Reference + lockId, err := cache.GetOrLockGitReferences("test-repo", "test-lock-id", &references) + assert.NoError(t, err) + assert.Equal(t, lockId, "test-lock-id") + assert.NotEqual(t, "", lockId, "Lock id should be set") + cache.revisionCacheLockTimeout = 10 * time.Second + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 1}) + }) + + t.Run("Test cache lock error", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + fixtures.cache.revisionCacheLockTimeout = 10 * time.Second + fixtures.mockCache.RedisClient.On("Set", mock.Anything).Unset() + fixtures.mockCache.RedisClient.On("Set", mock.Anything).Return(errors.New("test cache error")).Once(). + On("Set", mock.Anything).Return(nil) + var references []*plumbing.Reference + lockId, err := cache.GetOrLockGitReferences("test-repo", "test-lock-id", &references) + assert.NoError(t, err) + assert.Equal(t, lockId, "test-lock-id") + assert.NotEqual(t, "", lockId, "Lock id should be set") + fixtures.mockCache.RedisClient.AssertNumberOfCalls(t, "Set", 2) + fixtures.mockCache.RedisClient.AssertNumberOfCalls(t, "Get", 4) + }) +} + +func TestUnlockGitReferences(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + + t.Run("Test not locked", func(t *testing.T) { + err := cache.UnlockGitReferences("test-repo", "") + assert.Error(t, err) + assert.Contains(t, err.Error(), "key is missing") + }) + + t.Run("Test unlock", func(t *testing.T) { + // Get lock + var references []*plumbing.Reference + lockId, err := cache.GetOrLockGitReferences("test-repo", "test-lock-id", &references) + assert.NoError(t, err) + assert.Equal(t, lockId, "test-lock-id") + assert.NotEqual(t, "", lockId, "Lock id should be set") + // Release lock + err = cache.UnlockGitReferences("test-repo", lockId) + assert.NoError(t, err) + }) +} + +func TestSetHelmIndex(t *testing.T) { + t.Run("SetHelmIndex with valid data", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + err := fixtures.cache.SetHelmIndex("test-repo", []byte("test-data")) + assert.NoError(t, err) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalSets: 1}) + }) + t.Run("SetHelmIndex with nil", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + err := fixtures.cache.SetHelmIndex("test-repo", nil) + assert.Error(t, err, "nil data should not be cached") + var indexData []byte + err = fixtures.cache.GetHelmIndex("test-repo", &indexData) + assert.Error(t, err) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1}) + }) +} + +func TestRevisionChartDetails(t *testing.T) { + t.Run("GetRevisionChartDetails cache miss", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + details, err := fixtures.cache.GetRevisionChartDetails("test-repo", "test-revision", "v1.0.0") + assert.ErrorAs(t, err, &ErrCacheMiss) + assert.Equal(t, &appv1.ChartDetails{}, details) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1}) + }) + t.Run("GetRevisionChartDetails cache miss local", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + expectedItem := &appv1.ChartDetails{ + Description: "test-chart", + Home: "v1.0.0", + Maintainers: []string{"test-maintainer"}, + } + err := cache.cache.SetItem( + revisionChartDetailsKey("test-repo", "test-revision", "v1.0.0"), + expectedItem, + &cacheutil.CacheActionOpts{Expiration: 30 * time.Second}) + assert.NoError(t, err) + details, err := fixtures.cache.GetRevisionChartDetails("test-repo", "test-revision", "v1.0.0") + assert.NoError(t, err) + assert.Equal(t, expectedItem, details) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1, ExternalSets: 1}) + }) + + t.Run("GetRevisionChartDetails cache hit local", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + expectedItem := &appv1.ChartDetails{ + Description: "test-chart", + Home: "v1.0.0", + Maintainers: []string{"test-maintainer"}, + } + err := cache.cache.SetItem( + revisionChartDetailsKey("test-repo", "test-revision", "v1.0.0"), + expectedItem, + &cacheutil.CacheActionOpts{Expiration: 30 * time.Second}) + assert.NoError(t, err) + details, err := fixtures.cache.GetRevisionChartDetails("test-repo", "test-revision", "v1.0.0") + assert.NoError(t, err) + assert.Equal(t, expectedItem, details) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1, ExternalSets: 1}) + }) + + t.Run("SetRevisionChartDetails", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + expectedItem := &appv1.ChartDetails{ + Description: "test-chart", + Home: "v1.0.0", + Maintainers: []string{"test-maintainer"}, + } + err := fixtures.cache.SetRevisionChartDetails("test-repo", "test-revision", "v1.0.0", expectedItem) + assert.NoError(t, err) + details, err := fixtures.cache.GetRevisionChartDetails("test-repo", "test-revision", "v1.0.0") + assert.NoError(t, err) + assert.Equal(t, expectedItem, details) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1, ExternalSets: 1}) + }) + +} + +func TestGetGitDirectories(t *testing.T) { + t.Run("GetGitDirectories cache miss", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + directories, err := fixtures.cache.GetGitDirectories("test-repo", "test-revision") + assert.ErrorAs(t, err, &ErrCacheMiss) + assert.Equal(t, 0, len(directories)) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1}) + }) + t.Run("GetGitDirectories cache miss local", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + expectedItem := []string{"test/dir", "test/dir2"} + err := cache.cache.SetItem( + gitDirectoriesKey("test-repo", "test-revision"), + expectedItem, + &cacheutil.CacheActionOpts{Expiration: 30 * time.Second}) + assert.NoError(t, err) + directories, err := fixtures.cache.GetGitDirectories("test-repo", "test-revision") + assert.NoError(t, err) + assert.Equal(t, expectedItem, directories) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1, ExternalSets: 1}) + }) + + t.Run("GetGitDirectories cache hit local", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + expectedItem := []string{"test/dir", "test/dir2"} + err := cache.cache.SetItem( + gitDirectoriesKey("test-repo", "test-revision"), + expectedItem, + &cacheutil.CacheActionOpts{Expiration: 30 * time.Second}) + assert.NoError(t, err) + directories, err := fixtures.cache.GetGitDirectories("test-repo", "test-revision") + assert.NoError(t, err) + assert.Equal(t, expectedItem, directories) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1, ExternalSets: 1}) + }) + + t.Run("SetGitDirectories", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + expectedItem := []string{"test/dir", "test/dir2"} + err := fixtures.cache.SetGitDirectories("test-repo", "test-revision", expectedItem) + assert.NoError(t, err) + directories, err := fixtures.cache.GetGitDirectories("test-repo", "test-revision") + assert.NoError(t, err) + assert.Equal(t, expectedItem, directories) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1, ExternalSets: 1}) + }) + +} + +func TestGetGitFiles(t *testing.T) { + t.Run("GetGitFiles cache miss", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + directories, err := fixtures.cache.GetGitFiles("test-repo", "test-revision", "*.json") + assert.ErrorAs(t, err, &ErrCacheMiss) + assert.Equal(t, 0, len(directories)) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1}) + }) + t.Run("GetGitFiles cache hit", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + cache := fixtures.cache + expectedItem := map[string][]byte{"test/file.json": []byte("\"test\":\"contents\""), "test/file1.json": []byte("\"test1\":\"contents1\"")} + err := cache.cache.SetItem( + gitFilesKey("test-repo", "test-revision", "*.json"), + expectedItem, + &cacheutil.CacheActionOpts{Expiration: 30 * time.Second}) + assert.NoError(t, err) + files, err := fixtures.cache.GetGitFiles("test-repo", "test-revision", "*.json") + assert.NoError(t, err) + assert.Equal(t, expectedItem, files) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1, ExternalSets: 1}) + }) + + t.Run("SetGitFiles", func(t *testing.T) { + fixtures := newFixtures() + t.Cleanup(fixtures.mockCache.StopRedisCallback) + expectedItem := map[string][]byte{"test/file.json": []byte("\"test\":\"contents\""), "test/file1.json": []byte("\"test1\":\"contents1\"")} + err := fixtures.cache.SetGitFiles("test-repo", "test-revision", "*.json", expectedItem) + assert.NoError(t, err) + files, err := fixtures.cache.GetGitFiles("test-repo", "test-revision", "*.json") + assert.NoError(t, err) + assert.Equal(t, expectedItem, files) + fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1, ExternalSets: 1}) + }) + +} 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 f2bf09722680d..5b43d6a24ac76 100644 --- a/reposerver/gpgwatcher.go +++ b/reposerver/gpgwatcher.go @@ -19,9 +19,13 @@ 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 watcher.Close() + defer func(watcher *fsnotify.Watcher) { + if err = watcher.Close(); err != nil { + log.Errorf("Error closing watcher: %v", err) + } + }(watcher) done := make(chan bool) go func() { @@ -31,10 +35,10 @@ func StartGPGWatcher(sourcePath string) error { if !ok { return } - if event.Op&fsnotify.Create == fsnotify.Create || event.Op&fsnotify.Remove == fsnotify.Remove { + if event.Has(fsnotify.Create) || event.Has(fsnotify.Remove) { // In case our watched path is re-created (i.e. during e2e tests), we need to watch again // For more robustness, we retry re-creating the watcher up to maxRecreateRetries - if event.Name == sourcePath && event.Op&fsnotify.Remove == fsnotify.Remove { + if event.Name == sourcePath && event.Has(fsnotify.Remove) { log.Warnf("Re-creating watcher on %s", sourcePath) attempt := 0 for { @@ -79,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/metrics/metrics.go b/reposerver/metrics/metrics.go index e629b75e63d3c..44f3dbd01e1bb 100644 --- a/reposerver/metrics/metrics.go +++ b/reposerver/metrics/metrics.go @@ -12,6 +12,7 @@ import ( type MetricsServer struct { handler http.Handler + gitFetchFailCounter *prometheus.CounterVec gitRequestCounter *prometheus.CounterVec gitRequestHistogram *prometheus.HistogramVec repoPendingRequestsGauge *prometheus.GaugeVec @@ -32,6 +33,15 @@ func NewMetricsServer() *MetricsServer { registry.MustRegister(collectors.NewProcessCollector(collectors.ProcessCollectorOpts{})) registry.MustRegister(collectors.NewGoCollector()) + gitFetchFailCounter := prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "argocd_git_fetch_fail_total", + Help: "Number of git fetch requests failures by repo server", + }, + []string{"repo", "revision"}, + ) + registry.MustRegister(gitFetchFailCounter) + gitRequestCounter := prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "argocd_git_request_total", @@ -81,6 +91,7 @@ func NewMetricsServer() *MetricsServer { return &MetricsServer{ handler: promhttp.HandlerFor(registry, promhttp.HandlerOpts{}), + gitFetchFailCounter: gitFetchFailCounter, gitRequestCounter: gitRequestCounter, gitRequestHistogram: gitRequestHistogram, repoPendingRequestsGauge: repoPendingRequestsGauge, @@ -93,6 +104,10 @@ func (m *MetricsServer) GetHandler() http.Handler { return m.handler } +func (m *MetricsServer) IncGitFetchFail(repo string, revision string) { + m.gitFetchFailCounter.WithLabelValues(repo, revision).Inc() +} + // IncGitRequest increments the git requests counter func (m *MetricsServer) IncGitRequest(repo string, requestType GitRequestType) { m.gitRequestCounter.WithLabelValues(repo, string(requestType)).Inc() diff --git a/reposerver/repository/chart.go b/reposerver/repository/chart.go new file mode 100644 index 0000000000000..f4bcf48fba569 --- /dev/null +++ b/reposerver/repository/chart.go @@ -0,0 +1,30 @@ +package repository + +import ( + "fmt" + "strings" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "sigs.k8s.io/yaml" +) + +func getChartDetails(chartYAML string) (*v1alpha1.ChartDetails, error) { + var chart Chart + err := yaml.Unmarshal([]byte(chartYAML), &chart) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal chart: %w", err) + } + var maintainers []string + for _, maintainer := range chart.Maintainers { + if maintainer.Email != "" { + maintainers = append(maintainers, strings.Trim(fmt.Sprintf("%v <%v>", maintainer.Name, maintainer.Email), " ")) + } else { + maintainers = append(maintainers, fmt.Sprintf("%v", maintainer.Name)) + } + } + return &v1alpha1.ChartDetails{ + Description: chart.Description, + Maintainers: maintainers, + Home: chart.Home, + }, nil +} diff --git a/reposerver/repository/chart_test.go b/reposerver/repository/chart_test.go new file mode 100644 index 0000000000000..b22e7c21bede5 --- /dev/null +++ b/reposerver/repository/chart_test.go @@ -0,0 +1,63 @@ +package repository + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_getChartDetailsNotSet(t *testing.T) { + chart1 := `apiVersion: v3 +name: mychart +version: 0.0.0` + + cd, err := getChartDetails(chart1) + assert.NoError(t, err) + assert.Equal(t, cd.Description, "") + assert.Equal(t, cd.Maintainers, []string(nil)) + assert.Equal(t, cd.Home, "") +} + +func Test_getChartDetailsSet(t *testing.T) { + chart1 := `apiVersion: v3 +name: mychart +version: 0.0.0 +description: a good chart +home: https://example.com +maintainers: +- name: alex + email: example@example.com +` + + cd, err := getChartDetails(chart1) + assert.NoError(t, err) + assert.Equal(t, cd.Description, "a good chart") + assert.Equal(t, cd.Maintainers, []string{"alex "}) + assert.Equal(t, cd.Home, "https://example.com") + + chart1 = `apiVersion: v3 +name: mychart +version: 0.0.0 +description: a good chart +home: https://example.com +maintainers: +- name: alex +` + cd, err = getChartDetails(chart1) + assert.NoError(t, err) + assert.Equal(t, cd.Maintainers, []string{"alex"}) +} + +func Test_getChartDetailsBad(t *testing.T) { + chart1 := `apiVersion: v3 +name: mychart +version: 0.0.0 +description: a good chart +home: https://example.com +maintainers: alex +` + + cd, err := getChartDetails(chart1) + assert.Error(t, err) + assert.Nil(t, cd) +} diff --git a/reposerver/repository/lock.go b/reposerver/repository/lock.go index 05eddf667d82a..fa8da9c3e5089 100644 --- a/reposerver/repository/lock.go +++ b/reposerver/repository/lock.go @@ -55,7 +55,7 @@ func (r *repositoryLock) Lock(path string, revision string, allowConcurrent bool initCloser, err := init() if err != nil { state.cond.L.Unlock() - return nil, err + return nil, fmt.Errorf("failed to initialize repository resources: %w", err) } state.initCloser = initCloser state.revision = revision diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index 19a30f7182cda..e962e811ee2b5 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -10,31 +10,20 @@ import ( "io/fs" "net/url" "os" - "os/exec" "path" "path/filepath" "regexp" "strings" "time" - "github.com/golang/protobuf/ptypes/empty" - - kubeyaml "k8s.io/apimachinery/pkg/util/yaml" - - "k8s.io/apimachinery/pkg/api/resource" - - "github.com/argoproj/argo-cd/v2/common" - "github.com/argoproj/argo-cd/v2/util/io/files" - "github.com/argoproj/argo-cd/v2/util/manifeststream" - "github.com/Masterminds/semver/v3" "github.com/TomOnTime/utfutil" "github.com/argoproj/gitops-engine/pkg/utils/kube" textutils "github.com/argoproj/gitops-engine/pkg/utils/text" "github.com/argoproj/pkg/sync" jsonpatch "github.com/evanphx/json-patch" - "github.com/ghodss/yaml" gogit "github.com/go-git/go-git/v5" + "github.com/golang/protobuf/ptypes/empty" "github.com/google/go-jsonnet" "github.com/google/uuid" grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry" @@ -42,29 +31,34 @@ import ( "golang.org/x/sync/semaphore" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "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" + kubeyaml "k8s.io/apimachinery/pkg/util/yaml" + "sigs.k8s.io/yaml" pluginclient "github.com/argoproj/argo-cd/v2/cmpserver/apiclient" + "github.com/argoproj/argo-cd/v2/common" "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" - reposervercache "github.com/argoproj/argo-cd/v2/reposerver/cache" "github.com/argoproj/argo-cd/v2/reposerver/metrics" "github.com/argoproj/argo-cd/v2/util/app/discovery" argopath "github.com/argoproj/argo-cd/v2/util/app/path" "github.com/argoproj/argo-cd/v2/util/argo" "github.com/argoproj/argo-cd/v2/util/cmp" - executil "github.com/argoproj/argo-cd/v2/util/exec" + "github.com/argoproj/argo-cd/v2/util/env" "github.com/argoproj/argo-cd/v2/util/git" "github.com/argoproj/argo-cd/v2/util/glob" "github.com/argoproj/argo-cd/v2/util/gpg" "github.com/argoproj/argo-cd/v2/util/grpc" "github.com/argoproj/argo-cd/v2/util/helm" "github.com/argoproj/argo-cd/v2/util/io" + "github.com/argoproj/argo-cd/v2/util/io/files" pathutil "github.com/argoproj/argo-cd/v2/util/io/path" "github.com/argoproj/argo-cd/v2/util/kustomize" + "github.com/argoproj/argo-cd/v2/util/manifeststream" "github.com/argoproj/argo-cd/v2/util/text" ) @@ -77,7 +71,12 @@ const ( ociPrefix = "oci://" ) -var ErrExceededMaxCombinedManifestFileSize = errors.New("exceeded max combined manifest file size") +var ( + ErrExceededMaxCombinedManifestFileSize = errors.New("exceeded max combined manifest file size") + // helmConcurrencyDefault if true then helm concurrent manifest generation is enabled + // TODO: remove env variable and usage of .argocd-allow-concurrency once we are sure that it is safe to enable it by default + helmConcurrencyDefault = env.ParseBoolFromEnv("ARGOCD_HELM_ALLOW_CONCURRENCY", false) +) // Service implements ManifestService interface type Service struct { @@ -87,7 +86,7 @@ type Service struct { chartPaths io.TempPaths gitRepoInitializer func(rootPath string) goio.Closer repoLock *repositoryLock - cache *reposervercache.Cache + cache *cache.Cache parallelismLimitSemaphore *semaphore.Weighted metricsServer *metrics.MetricsServer resourceTracking argo.ResourceTracking @@ -109,10 +108,13 @@ type RepoServerInitConstants struct { AllowOutOfBoundsSymlinks bool StreamedManifestMaxExtractedSize int64 StreamedManifestMaxTarSize int64 + HelmManifestMaxExtractedSize int64 + HelmRegistryMaxIndexSize int64 + DisableHelmManifestMaxExtractedSize bool } // NewService returns a new instance of the Manifest service -func NewService(metricsServer *metrics.MetricsServer, cache *reposervercache.Cache, initConstants RepoServerInitConstants, resourceTracking argo.ResourceTracking, gitCredsStore git.CredsStore, rootDir string) *Service { +func NewService(metricsServer *metrics.MetricsServer, cache *cache.Cache, initConstants RepoServerInitConstants, resourceTracking argo.ResourceTracking, gitCredsStore git.CredsStore, rootDir string) *Service { var parallelismLimitSemaphore *semaphore.Weighted if initConstants.ParallelismLimit > 0 { parallelismLimitSemaphore = semaphore.NewWeighted(initConstants.ParallelismLimit) @@ -149,16 +151,16 @@ func (s *Service) Init() error { // give itself read permissions to list previously written directories err = os.Chmod(s.rootDir, 0700) } - var files []fs.DirEntry + var dirEntries []fs.DirEntry if err == nil { - files, err = os.ReadDir(s.rootDir) + dirEntries, err = os.ReadDir(s.rootDir) } if err != nil { log.Warnf("Failed to restore cloned repositories paths: %v", err) return nil } - for _, file := range files { + for _, file := range dirEntries { if !file.IsDir() { continue } @@ -175,11 +177,11 @@ func (s *Service) Init() error { return os.Chmod(s.rootDir, 0300) } -// List a subset of the refs (currently, branches and tags) of a git repo +// ListRefs List a subset of the refs (currently, branches and tags) of a git repo func (s *Service) ListRefs(ctx context.Context, q *apiclient.ListRefsRequest) (*apiclient.Refs, error) { gitClient, err := s.newClient(q.Repo) if err != nil { - return nil, err + return nil, fmt.Errorf("error creating git client: %w", err) } s.metricsServer.IncPendingRepoRequest(q.Repo.Repo) @@ -202,7 +204,7 @@ func (s *Service) ListRefs(ctx context.Context, q *apiclient.ListRefsRequest) (* func (s *Service) ListApps(ctx context.Context, q *apiclient.ListAppsRequest) (*apiclient.AppList, error) { gitClient, commitSHA, err := s.newClientResolveRevision(q.Repo, q.Revision) if err != nil { - return nil, err + return nil, fmt.Errorf("error setting up git client and resolving given revision: %w", err) } if apps, err := s.cache.ListApps(q.Repo.Repo, commitSHA); err == nil { log.Infof("cache hit: %s/%s", q.Repo.Repo, q.Revision) @@ -217,13 +219,13 @@ func (s *Service) ListApps(ctx context.Context, q *apiclient.ListAppsRequest) (* }) if err != nil { - return nil, err + return nil, fmt.Errorf("error acquiring repository lock: %w", err) } defer io.Close(closer) - apps, err := discovery.Discover(ctx, gitClient.Root(), q.EnabledSourceTypes, s.initConstants.CMPTarExcludedGlobs) + apps, err := discovery.Discover(ctx, gitClient.Root(), gitClient.Root(), q.EnabledSourceTypes, s.initConstants.CMPTarExcludedGlobs, []string{}) if err != nil { - return nil, err + return nil, fmt.Errorf("error discovering applications: %w", err) } err = s.cache.SetApps(q.Repo.Repo, commitSHA, apps) if err != nil { @@ -242,7 +244,7 @@ func (s *Service) ListPlugins(ctx context.Context, _ *empty.Empty) (*apiclient.P return nil, fmt.Errorf("failed to get plugins from dir %v, error=%w", pluginSockFilePath, err) } - plugins := []*apiclient.PluginInfo{} + var plugins []*apiclient.PluginInfo for _, file := range sockFiles { if file.Type() == os.ModeSocket { plugins = append(plugins, &apiclient.PluginInfo{Name: strings.TrimSuffix(file.Name(), ".sock")}) @@ -287,34 +289,42 @@ func (s *Service) runRepoOperation( repo *v1alpha1.Repository, source *v1alpha1.ApplicationSource, verifyCommit bool, - cacheFn func(cacheKey string, firstInvocation bool) (bool, error), + cacheFn func(cacheKey string, refSourceCommitSHAs cache.ResolvedRevisions, firstInvocation bool) (bool, error), operation func(repoRoot, commitSHA, cacheKey string, ctxSrc operationContextSrc) error, settings operationSettings, - hasMultipleSources bool) error { + hasMultipleSources bool, + refSources map[string]*v1alpha1.RefTarget) error { if sanitizer, ok := grpc.SanitizerFromContext(ctx); ok { - // make sure randomized path replaced with '.' in the error message - sanitizer.AddRegexReplacement(regexp.MustCompile(`(`+regexp.QuoteMeta(s.rootDir)+`/.*?)/`), ".") + // make sure a randomized path replaced with '.' in the error message + sanitizer.AddRegexReplacement(getRepoSanitizerRegex(s.rootDir), "") } 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() { helmClient, revision, err = s.newHelmClientResolveRevision(repo, revision, source.Chart, settings.noCache || settings.noRevisionCache) if err != nil { 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, gitClientOpts) + if err != nil { + return err + } + if !settings.noCache { - if ok, err := cacheFn(revision, true); ok { + if ok, err := cacheFn(revision, repoRefs, true); ok { return err } } @@ -330,14 +340,6 @@ func (s *Service) runRepoOperation( defer settings.sem.Release(1) } - // do not generate manifests if Path and Chart fields are not set for a source in Multiple Sources - if hasMultipleSources && source.Path == "" && source.Chart == "" { - log.WithFields(map[string]interface{}{ - "source": source, - }).Debugf("not generating manifests as path and chart fields are empty") - return nil - } - if source.IsHelm() { if settings.noCache { err = helmClient.CleanChartCache(source.Chart, revision) @@ -349,7 +351,7 @@ func (s *Service) runRepoOperation( if source.Helm != nil { helmPassCredentials = source.Helm.PassCredentials } - chartPath, closer, err := helmClient.ExtractChart(source.Chart, revision, helmPassCredentials) + chartPath, closer, err := helmClient.ExtractChart(source.Chart, revision, helmPassCredentials, s.initConstants.HelmManifestMaxExtractedSize, s.initConstants.DisableHelmManifestMaxExtractedSize) if err != nil { return err } @@ -403,14 +405,20 @@ func (s *Service) runRepoOperation( } } - commitSHA, err := gitClient.CommitSHA() - if err != nil { - return err + var commitSHA string + if hasMultipleSources { + commitSHA = revision + } else { + commit, err := gitClient.CommitSHA() + if err != nil { + return fmt.Errorf("failed to get commit SHA: %w", err) + } + commitSHA = commit } // double-check locking if !settings.noCache { - if ok, err := cacheFn(revision, false); ok { + if ok, err := cacheFn(revision, repoRefs, false); ok { return err } } @@ -420,7 +428,16 @@ func (s *Service) runRepoOperation( return operation(gitClient.Root(), commitSHA, revision, func() (*operationContext, error) { var signature string if verifyCommit { - signature, err = gitClient.VerifyCommitSignature(revision) + // When the revision is an annotated tag, we need to pass the unresolved revision (i.e. the tag name) + // to the verification routine. For everything else, we work with the SHA that the target revision is + // pointing to (i.e. the resolved revision). + var rev string + if gitClient.IsAnnotatedTag(revision) { + rev = unresolvedRevision + } else { + rev = revision + } + signature, err = gitClient.VerifyCommitSignature(rev) if err != nil { return nil, err } @@ -434,11 +451,78 @@ func (s *Service) runRepoOperation( } } +func getRepoSanitizerRegex(rootDir string) *regexp.Regexp { + // This regex assumes that the sensitive part of the path (the component immediately after "rootDir") contains no + // spaces. This assumption allows us to avoid sanitizing "more info" in "/tmp/_argocd-repo/SENSITIVE more info". + // + // The no-spaces assumption holds for our actual use case, which is "/tmp/_argocd-repo/{random UUID}". The UUID will + // only ever contain digits and hyphens. + return regexp.MustCompile(regexp.QuoteMeta(rootDir) + `/[^ /]*`) +} + +type gitClientGetter func(repo *v1alpha1.Repository, revision string, opts ...git.ClientOpts) (git.Client, string, error) + +// resolveReferencedSources resolves the revisions for the given referenced sources. This lets us invalidate the cached +// when one or more referenced sources change. +// +// 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, gitClientOpts git.ClientOpts) (map[string]string, error) { + repoRefs := make(map[string]string) + if !hasMultipleSources || source == nil { + return repoRefs, nil + } + + for _, valueFile := range source.ValueFiles { + if strings.HasPrefix(valueFile, "$") { + refVar := strings.Split(valueFile, "/")[0] + + refSourceMapping, ok := refSources[refVar] + if !ok { + if len(refSources) == 0 { + return nil, fmt.Errorf("source referenced %q, but no source has a 'ref' field defined", refVar) + } + refKeys := make([]string, 0) + for refKey := range refSources { + refKeys = append(refKeys, refKey) + } + return nil, fmt.Errorf("source referenced %q, which is not one of the available sources (%s)", refVar, strings.Join(refKeys, ", ")) + } + if refSourceMapping.Chart != "" { + return nil, fmt.Errorf("source has a 'chart' field defined, but Helm charts are not yet not supported for 'ref' sources") + } + normalizedRepoURL := git.NormalizeGitURL(refSourceMapping.Repo.Repo) + _, ok = repoRefs[normalizedRepoURL] + if !ok { + _, 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) + } + + repoRefs[normalizedRepoURL] = referencedCommitSHA + } + } + } + return repoRefs, nil +} + func (s *Service) GenerateManifest(ctx context.Context, q *apiclient.ManifestRequest) (*apiclient.ManifestResponse, error) { var res *apiclient.ManifestResponse var err error - cacheFn := func(cacheKey string, firstInvocation bool) (bool, error) { - ok, resp, err := s.getManifestCacheEntry(cacheKey, q, firstInvocation) + + // 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 return ok, err } @@ -447,6 +531,17 @@ func (s *Service) GenerateManifest(ctx context.Context, q *apiclient.ManifestReq var promise *ManifestResponsePromise operation := func(repoRoot, commitSHA, cacheKey string, ctxSrc operationContextSrc) error { + // do not generate manifests if Path and Chart fields are not set for a source in Multiple Sources + if q.HasMultipleSources && q.ApplicationSource.Path == "" && q.ApplicationSource.Chart == "" { + log.WithFields(map[string]interface{}{ + "source": q.ApplicationSource, + }).Debugf("not generating manifests as path and chart fields are empty") + res = &apiclient.ManifestResponse{ + Revision: commitSHA, + } + return nil + } + promise = s.runManifestGen(ctx, repoRoot, commitSHA, cacheKey, ctxSrc, q) // The fist channel to send the message will resume this operation. // The main purpose for using channels here is to be able to unlock @@ -465,7 +560,7 @@ func (s *Service) GenerateManifest(ctx context.Context, q *apiclient.ManifestReq } settings := operationSettings{sem: s.parallelismLimitSemaphore, noCache: q.NoCache, noRevisionCache: q.NoRevisionCache, allowConcurrent: q.ApplicationSource.AllowsConcurrentProcessing()} - err = s.runRepoOperation(ctx, q.Revision, q.Repo, q.ApplicationSource, q.VerifySignature, cacheFn, operation, settings, q.HasMultipleSources) + err = s.runRepoOperation(ctx, q.Revision, q.Repo, q.ApplicationSource, q.VerifySignature, cacheFn, operation, settings, q.HasMultipleSources, q.RefSources) // if the tarDoneCh message is sent it means that the manifest // generation is being managed by the cmp-server. In this case @@ -479,10 +574,6 @@ func (s *Service) GenerateManifest(ctx context.Context, q *apiclient.ManifestReq return nil, err } } - - if q.HasMultipleSources && err == nil && res == nil { - res = &apiclient.ManifestResponse{} - } return res, err } @@ -596,9 +687,12 @@ func (s *Service) runManifestGen(ctx context.Context, repoRoot, commitSHA, cache } type repoRef struct { - revision string + // revision is the git revision - can be any valid revision like a branch, tag, or commit SHA. + revision string + // commitSHA is the actual commit to which revision refers. commitSHA string - key string + // key is the name of the key which was used to reference this repo. + key string } func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA, cacheKey string, opContextSrc operationContextSrc, q *apiclient.ManifestRequest, ch *generateManifestCh) { @@ -610,13 +704,15 @@ func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA, // GenerateManifests mutates the source (applies overrides). Those overrides shouldn't be reflected in the cache // key. Overrides will break the cache anyway, because changes to overrides will change the revision. appSourceCopy := q.ApplicationSource.DeepCopy() + repoRefs := make(map[string]repoRef) var manifestGenResult *apiclient.ManifestResponse opContext, err := opContextSrc() if err == nil { + // Much of the multi-source handling logic is duplicated in resolveReferencedSources. If making changes here, + // check whether they should be replicated in resolveReferencedSources. if q.HasMultipleSources { if q.ApplicationSource.Helm != nil { - repoRefs := make(map[string]repoRef) // Checkout every one of the referenced sources to the target revision before generating Manifests for _, valueFile := range q.ApplicationSource.Helm.ValueFiles { @@ -647,9 +743,10 @@ 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 { - ch.errCh <- fmt.Errorf("failed to get git client for repo %s", q.Repo.Repo) + 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) return } @@ -702,17 +799,28 @@ func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA, manifestGenResult, err = GenerateManifests(ctx, opContext.appPath, repoRoot, commitSHA, q, false, s.gitCredsStore, s.initConstants.MaxCombinedDirectoryManifestsSize, s.gitRepoPaths, WithCMPTarDoneChannel(ch.tarDoneCh), WithCMPTarExcludedGlobs(s.initConstants.CMPTarExcludedGlobs)) } + refSourceCommitSHAs := make(map[string]string) + if len(repoRefs) > 0 { + for normalizedURL, repoRef := range repoRefs { + refSourceCommitSHAs[normalizedURL] = repoRef.commitSHA + } + } if err != nil { + logCtx := log.WithFields(log.Fields{ + "application": q.AppName, + "appNamespace": q.Namespace, + }) + // If manifest generation error caching is enabled if s.initConstants.PauseGenerationAfterFailedGenerationAttempts > 0 { - cache.LogDebugManifestCacheKeyFields("getting manifests cache", "GenerateManifests error", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName) + cache.LogDebugManifestCacheKeyFields("getting manifests cache", "GenerateManifests error", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, refSourceCommitSHAs) // Retrieve a new copy (if available) of the cached response: this ensures we are updating the latest copy of the cache, // rather than a copy of the cache that occurred before (a potentially lengthy) manifest generation. innerRes := &cache.CachedManifestResponse{} - cacheErr := s.cache.GetManifests(cacheKey, appSourceCopy, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, innerRes) - if cacheErr != nil && cacheErr != reposervercache.ErrCacheMiss { - log.Warnf("manifest cache set error %s: %v", appSourceCopy.String(), cacheErr) + cacheErr := s.cache.GetManifests(cacheKey, appSourceCopy, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, innerRes, refSourceCommitSHAs) + if cacheErr != nil && cacheErr != cache.ErrCacheMiss { + logCtx.Warnf("manifest cache get error %s: %v", appSourceCopy.String(), cacheErr) ch.errCh <- cacheErr return } @@ -723,14 +831,14 @@ func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA, innerRes.FirstFailureTimestamp = s.now().Unix() } - cache.LogDebugManifestCacheKeyFields("setting manifests cache", "GenerateManifests error", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName) + cache.LogDebugManifestCacheKeyFields("setting manifests cache", "GenerateManifests error", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, refSourceCommitSHAs) // Update the cache to include failure information innerRes.NumberOfConsecutiveFailures++ innerRes.MostRecentError = err.Error() - cacheErr = s.cache.SetManifests(cacheKey, appSourceCopy, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, innerRes) + cacheErr = s.cache.SetManifests(cacheKey, appSourceCopy, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, innerRes, refSourceCommitSHAs) if cacheErr != nil { - log.Warnf("manifest cache set error %s: %v", appSourceCopy.String(), cacheErr) + logCtx.Warnf("manifest cache set error %s: %v", appSourceCopy.String(), cacheErr) ch.errCh <- cacheErr return } @@ -740,7 +848,7 @@ func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA, return } - cache.LogDebugManifestCacheKeyFields("setting manifests cache", "fresh GenerateManifests response", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName) + cache.LogDebugManifestCacheKeyFields("setting manifests cache", "fresh GenerateManifests response", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, refSourceCommitSHAs) // Otherwise, no error occurred, so ensure the manifest generation error data in the cache entry is reset before we cache the value manifestGenCacheEntry := cache.CachedManifestResponse{ @@ -752,7 +860,7 @@ func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA, } manifestGenResult.Revision = commitSHA manifestGenResult.VerifyResult = opContext.verificationResult - err = s.cache.SetManifests(cacheKey, appSourceCopy, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, &manifestGenCacheEntry) + err = s.cache.SetManifests(cacheKey, appSourceCopy, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, &manifestGenCacheEntry, refSourceCommitSHAs) if err != nil { log.Warnf("manifest cache set error %s/%s: %v", appSourceCopy.String(), cacheKey, err) } @@ -765,11 +873,11 @@ func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA, // - If the cache is not empty, but the cache value is an error AND that generation error has expired // and returns true otherwise. // If true is returned, either the second or third parameter (but not both) will contain a value from the cache (a ManifestResponse, or error, respectively) -func (s *Service) getManifestCacheEntry(cacheKey string, q *apiclient.ManifestRequest, firstInvocation bool) (bool, *apiclient.ManifestResponse, error) { - cache.LogDebugManifestCacheKeyFields("getting manifests cache", "GenerateManifest API call", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName) +func (s *Service) getManifestCacheEntry(cacheKey string, q *apiclient.ManifestRequest, refSourceCommitSHAs cache.ResolvedRevisions, firstInvocation bool) (bool, *apiclient.ManifestResponse, error) { + cache.LogDebugManifestCacheKeyFields("getting manifests cache", "GenerateManifest API call", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, refSourceCommitSHAs) res := cache.CachedManifestResponse{} - err := s.cache.GetManifests(cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, &res) + err := s.cache.GetManifests(cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, &res, refSourceCommitSHAs) if err == nil { // The cache contains an existing value @@ -787,10 +895,10 @@ func (s *Service) getManifestCacheEntry(cacheKey string, q *apiclient.ManifestRe // After X minutes, reset the cache and retry the operation (e.g. perhaps the error is ephemeral and has passed) if elapsedTimeInMinutes >= s.initConstants.PauseGenerationOnFailureForMinutes { - cache.LogDebugManifestCacheKeyFields("deleting manifests cache", "manifest hash did not match or cached response is empty", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName) + cache.LogDebugManifestCacheKeyFields("deleting manifests cache", "manifest hash did not match or cached response is empty", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, refSourceCommitSHAs) // We can now try again, so reset the cache state and run the operation below - err = s.cache.DeleteManifests(cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName) + err = s.cache.DeleteManifests(cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, refSourceCommitSHAs) if err != nil { log.Warnf("manifest cache set error %s/%s: %v", q.ApplicationSource.String(), cacheKey, err) } @@ -803,10 +911,10 @@ func (s *Service) getManifestCacheEntry(cacheKey string, q *apiclient.ManifestRe if s.initConstants.PauseGenerationOnFailureForRequests > 0 && res.NumberOfCachedResponsesReturned > 0 { if res.NumberOfCachedResponsesReturned >= s.initConstants.PauseGenerationOnFailureForRequests { - cache.LogDebugManifestCacheKeyFields("deleting manifests cache", "reset after paused generation count", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName) + cache.LogDebugManifestCacheKeyFields("deleting manifests cache", "reset after paused generation count", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, refSourceCommitSHAs) // We can now try again, so reset the error cache state and run the operation below - err = s.cache.DeleteManifests(cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName) + err = s.cache.DeleteManifests(cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, refSourceCommitSHAs) if err != nil { log.Warnf("manifest cache set error %s/%s: %v", q.ApplicationSource.String(), cacheKey, err) } @@ -821,12 +929,12 @@ func (s *Service) getManifestCacheEntry(cacheKey string, q *apiclient.ManifestRe cachedErrorResponse := fmt.Errorf(cachedManifestGenerationPrefix+": %s", res.MostRecentError) if firstInvocation { - cache.LogDebugManifestCacheKeyFields("setting manifests cache", "update error count", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName) + cache.LogDebugManifestCacheKeyFields("setting manifests cache", "update error count", cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, refSourceCommitSHAs) // Increment the number of returned cached responses and push that new value to the cache // (if we have not already done so previously in this function) res.NumberOfCachedResponsesReturned++ - err = s.cache.SetManifests(cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, &res) + err = s.cache.SetManifests(cacheKey, q.ApplicationSource, q.RefSources, q, q.Namespace, q.TrackingMethod, q.AppLabelKey, q.AppName, &res, refSourceCommitSHAs) if err != nil { log.Warnf("manifest cache set error %s/%s: %v", q.ApplicationSource.String(), cacheKey, err) } @@ -846,7 +954,7 @@ func (s *Service) getManifestCacheEntry(cacheKey string, q *apiclient.ManifestRe return true, res.ManifestResponse, nil } - if err != reposervercache.ErrCacheMiss { + if err != cache.ErrCacheMiss { log.Warnf("manifest cache error %s: %v", q.ApplicationSource.String(), err) } else { log.Infof("manifest cache miss: %s/%s", q.ApplicationSource.String(), cacheKey) @@ -855,12 +963,52 @@ func (s *Service) getManifestCacheEntry(cacheKey string, q *apiclient.ManifestRe return false, nil, nil } -func getHelmRepos(repositories []*v1alpha1.Repository) []helm.HelmRepository { - repos := make([]helm.HelmRepository, 0) +func getHelmRepos(appPath string, repositories []*v1alpha1.Repository, helmRepoCreds []*v1alpha1.RepoCreds) ([]helm.HelmRepository, error) { + dependencies, err := getHelmDependencyRepos(appPath) + if err != nil { + return nil, fmt.Errorf("error retrieving helm dependency repos: %w", err) + } + reposByName := make(map[string]*v1alpha1.Repository) + reposByUrl := make(map[string]*v1alpha1.Repository) for _, repo := range repositories { + reposByUrl[repo.Repo] = repo + if repo.Name != "" { + reposByName[repo.Name] = repo + } + } + + repos := make([]helm.HelmRepository, 0) + for _, dep := range dependencies { + // find matching repo credentials by URL or name + repo, ok := reposByUrl[dep.Repo] + if !ok && dep.Name != "" { + repo, ok = reposByName[dep.Name] + } + if !ok { + // if no matching repo credentials found, use the repo creds from the credential list + repo = &v1alpha1.Repository{Repo: dep.Repo, Name: dep.Name, EnableOCI: dep.EnableOCI} + if repositoryCredential := getRepoCredential(helmRepoCreds, dep.Repo); repositoryCredential != nil { + repo.EnableOCI = repositoryCredential.EnableOCI + repo.Password = repositoryCredential.Password + repo.Username = repositoryCredential.Username + repo.SSHPrivateKey = repositoryCredential.SSHPrivateKey + repo.TLSClientCertData = repositoryCredential.TLSClientCertData + repo.TLSClientCertKey = repositoryCredential.TLSClientCertKey + } else if repo.EnableOCI { + // finally if repo is OCI and no credentials found, use the first OCI credential matching by hostname + // see https://github.com/argoproj/argo-cd/issues/14636 + for _, cred := range repositories { + if depURL, err := url.Parse("oci://" + dep.Repo); err == nil && cred.EnableOCI && depURL.Host == cred.Repo { + repo.Username = cred.Username + repo.Password = cred.Password + break + } + } + } + } repos = append(repos, helm.HelmRepository{Name: repo.Name, Repo: repo.Repo, Creds: repo.GetHelmCreds(), EnableOci: repo.EnableOCI}) } - return repos + return repos, nil } type dependencies struct { @@ -875,18 +1023,27 @@ func getHelmDependencyRepos(appPath string) ([]*v1alpha1.Repository, error) { repos := make([]*v1alpha1.Repository, 0) f, err := os.ReadFile(filepath.Join(appPath, "Chart.yaml")) if err != nil { - return nil, err + return nil, fmt.Errorf("error reading helm chart from %s: %w", filepath.Join(appPath, "Chart.yaml"), err) } d := &dependencies{} if err = yaml.Unmarshal(f, d); err != nil { - return nil, err + return nil, fmt.Errorf("error unmarshalling the helm chart while getting helm dependency repos: %w", err) } for _, r := range d.Dependencies { - if u, err := url.Parse(r.Repository); err == nil && (u.Scheme == "https" || u.Scheme == "oci") { + if strings.HasPrefix(r.Repository, "@") { + 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{ - Repo: r.Repository, + // trimming oci:// prefix since it is currently not supported by Argo CD (OCI repos just have no scheme) + Repo: strings.TrimPrefix(r.Repository, "oci://"), Name: sanitizeRepoName(r.Repository), EnableOCI: u.Scheme == "oci", } @@ -901,15 +1058,6 @@ func sanitizeRepoName(repoName string) string { return strings.ReplaceAll(repoName, "/", "-") } -func repoExists(repo string, repos []*v1alpha1.Repository) bool { - for _, r := range repos { - if strings.TrimPrefix(repo, ociPrefix) == strings.TrimPrefix(r.Repo, ociPrefix) { - return true - } - } - return false -} - func isConcurrencyAllowed(appPath string) bool { if _, err := os.Stat(path.Join(appPath, allowConcurrencyFile)); err == nil { return true @@ -927,9 +1075,9 @@ func runHelmBuild(appPath string, h helm.Helm) error { manifestGenerateLock.Lock(appPath) defer manifestGenerateLock.Unlock(appPath) - // the `helm dependency build` is potentially time consuming 1~2 seconds - // marker file is used to check if command already run to avoid running it again unnecessary - // file is removed when repository re-initialized (e.g. when another commit is processed) + // the `helm dependency build` is potentially a time-consuming 1~2 seconds, + // a marker file is used to check if command already run to avoid running it again unnecessarily + // the file is removed when repository is re-initialized (e.g. when another commit is processed) markerFile := path.Join(appPath, helmDepUpMarkerFile) _, err := os.Stat(markerFile) if err == nil { @@ -940,39 +1088,18 @@ func runHelmBuild(appPath string, h helm.Helm) error { err = h.DependencyBuild() if err != nil { - return err + return fmt.Errorf("error building helm chart dependencies: %w", err) } return os.WriteFile(markerFile, []byte("marker"), 0644) } -func populateRequestRepos(appPath string, q *apiclient.ManifestRequest) error { - repos, err := getHelmDependencyRepos(appPath) - if err != nil { - return err - } - - for _, r := range repos { - if !repoExists(r.Repo, q.Repos) { - repositoryCredential := getRepoCredential(q.HelmRepoCreds, r.Repo) - if repositoryCredential != nil { - if repositoryCredential.EnableOCI { - r.Repo = strings.TrimPrefix(r.Repo, ociPrefix) - } - r.EnableOCI = repositoryCredential.EnableOCI - r.Password = repositoryCredential.Password - r.Username = repositoryCredential.Username - r.SSHPrivateKey = repositoryCredential.SSHPrivateKey - r.TLSClientCertData = repositoryCredential.TLSClientCertData - r.TLSClientCertKey = repositoryCredential.TLSClientCertKey - } - q.Repos = append(q.Repos, r) - } - } - return nil +func isSourcePermitted(url string, repos []string) bool { + p := v1alpha1.AppProject{Spec: v1alpha1.AppProjectSpec{SourceRepos: repos}} + return p.IsSourcePermitted(v1alpha1.ApplicationSource{RepoURL: url}) } func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclient.ManifestRequest, isLocal bool, gitRepoPaths io.TempPaths) ([]*unstructured.Unstructured, error) { - concurrencyAllowed := isConcurrencyAllowed(appPath) + concurrencyAllowed := helmConcurrencyDefault || isConcurrencyAllowed(appPath) if !concurrencyAllowed { manifestGenerateLock.Lock(appPath) defer manifestGenerateLock.Unlock(appPath) @@ -982,7 +1109,7 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie // contain any underscore characters and must not exceed 53 characters. // We are not interested in the fully qualified application name while // templating, thus, we just use the name part of the identifier. - appName, _ := argo.ParseAppInstanceName(q.AppName, "") + appName, _ := argo.ParseInstanceName(q.AppName, "") templateOpts := &helm.TemplateOpts{ Name: appName, @@ -1007,15 +1134,15 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie resolvedValueFiles, err := getResolvedValueFiles(appPath, repoRoot, env, q.GetValuesFileSchemes(), appHelm.ValueFiles, q.RefSources, gitRepoPaths, appHelm.IgnoreMissingValueFiles) if err != nil { - return nil, err + return nil, fmt.Errorf("error resolving helm value files: %w", err) } templateOpts.Values = resolvedValueFiles - if appHelm.Values != "" { + if !appHelm.ValuesIsEmpty() { rand, err := uuid.NewRandom() if err != nil { - return nil, err + return nil, fmt.Errorf("error generating random filename for Helm values file: %w", err) } p := path.Join(os.TempDir(), rand.String()) defer func() { @@ -1024,9 +1151,9 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie _ = os.RemoveAll(p) } }() - err = os.WriteFile(p, []byte(appHelm.Values), 0644) + err = os.WriteFile(p, appHelm.ValuesYAML(), 0644) if err != nil { - return nil, err + return nil, fmt.Errorf("error writing helm values file: %w", err) } templateOpts.Values = append(templateOpts.Values, pathutil.ResolvedFilePath(p)) } @@ -1041,7 +1168,7 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie for _, p := range appHelm.FileParameters { resolvedPath, _, err := pathutil.ResolveValueFilePathOrUrl(appPath, repoRoot, env.Envsubst(p.Path), q.GetValuesFileSchemes()) if err != nil { - return nil, err + return nil, fmt.Errorf("error resolving helm value file path: %w", err) } templateOpts.SetFile[p.Name] = resolvedPath } @@ -1058,24 +1185,25 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie templateOpts.SetString[i] = env.Envsubst(j) } - if err := populateRequestRepos(appPath, q); err != nil { - return nil, fmt.Errorf("failed parsing dependencies: %v", err) - } - var proxy string if q.Repo != nil { proxy = q.Repo.Proxy } - h, err := helm.NewHelmApp(appPath, getHelmRepos(q.Repos), isLocal, version, proxy, passCredentials) + helmRepos, err := getHelmRepos(appPath, q.Repos, q.HelmRepoCreds) if err != nil { - return nil, err + return nil, fmt.Errorf("error getting helm repos: %w", err) + } + + h, err := helm.NewHelmApp(appPath, helmRepos, isLocal, version, proxy, passCredentials) + if err != nil { + return nil, fmt.Errorf("error initializing helm app object: %w", err) } defer h.Dispose() err = h.Init() if err != nil { - return nil, err + return nil, fmt.Errorf("error initializing helm app: %w", err) } out, err := h.Template(templateOpts) @@ -1091,6 +1219,24 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie } if err != nil { + var reposNotPermitted []string + // We do a sanity check here to give a nicer error message in case any of the Helm repositories are not permitted by + // the AppProject which the application is a part of + for _, repo := range helmRepos { + msg := err.Error() + + chartCannotBeReached := strings.Contains(msg, "is not a valid chart repository or cannot be reached") + couldNotDownloadChart := strings.Contains(msg, "could not download") + + if (chartCannotBeReached || couldNotDownloadChart) && !isSourcePermitted(repo.Repo, q.ProjectSourceRepos) { + reposNotPermitted = append(reposNotPermitted, repo.Repo) + } + } + + if len(reposNotPermitted) > 0 { + return nil, status.Errorf(codes.PermissionDenied, "helm repos %s are not permitted in project '%s'", strings.Join(reposNotPermitted, ", "), q.ProjectName) + } + return nil, err } @@ -1123,13 +1269,13 @@ func getResolvedValueFiles( // If the $-prefixed path appears to reference another source, do env substitution _after_ resolving that source. resolvedPath, err = getResolvedRefValueFile(rawValueFile, env, allowedValueFilesSchemas, referencedSource.Repo.Repo, gitRepoPaths) if err != nil { - return nil, err + return nil, fmt.Errorf("error resolving value file path: %w", err) } } else { // This will resolve val to an absolute path (or an URL) resolvedPath, isRemote, err = pathutil.ResolveValueFilePathOrUrl(appPath, repoRoot, env.Envsubst(rawValueFile), allowedValueFilesSchemas) if err != nil { - return nil, err + return nil, fmt.Errorf("error resolving value file path: %w", err) } } @@ -1166,7 +1312,7 @@ func getResolvedRefValueFile( // Resolve the path relative to the referenced repo and block any attempt at traversal. resolvedPath, _, err := pathutil.ResolveValueFilePathOrUrl(repoPath, repoPath, env.Envsubst(substitutedPath), allowedValueFilesSchemas) if err != nil { - return "", err + return "", fmt.Errorf("error resolving value file path: %w", err) } return resolvedPath, nil } @@ -1225,19 +1371,19 @@ func WithCMPTarExcludedGlobs(excludedGlobs []string) GenerateManifestOpt { func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string, q *apiclient.ManifestRequest, isLocal bool, gitCredsStore git.CredsStore, maxCombinedManifestQuantity resource.Quantity, gitRepoPaths io.TempPaths, opts ...GenerateManifestOpt) (*apiclient.ManifestResponse, error) { opt := newGenerateManifestOpt(opts...) var targetObjs []*unstructured.Unstructured - var dest *v1alpha1.ApplicationDestination resourceTracking := argo.NewResourceTracking() - appSourceType, err := GetAppSourceType(ctx, q.ApplicationSource, appPath, q.AppName, q.EnabledSourceTypes, opt.cmpTarExcludedGlobs) + env := newEnv(q, revision) + + appSourceType, err := GetAppSourceType(ctx, q.ApplicationSource, appPath, repoRoot, q.AppName, q.EnabledSourceTypes, opt.cmpTarExcludedGlobs, env.Environ()) if err != nil { - return nil, err + return nil, fmt.Errorf("error getting app source type: %w", err) } repoURL := "" if q.Repo != nil { repoURL = q.Repo.Repo } - env := newEnv(q, revision) switch appSourceType { case v1alpha1.ApplicationSourceTypeHelm: @@ -1247,31 +1393,17 @@ 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: - var plugin *v1alpha1.ConfigManagementPlugin - if q.ApplicationSource.Plugin != nil && q.ApplicationSource.Plugin.Name != "" { - plugin = findPlugin(q.Plugins, q.ApplicationSource.Plugin.Name) + pluginName := "" + if q.ApplicationSource.Plugin != nil { + pluginName = q.ApplicationSource.Plugin.Name } - if plugin != nil { - // argocd-cm deprecated plugin is being used - targetObjs, err = runConfigManagementPlugin(appPath, repoRoot, env, q, q.Repo.GetGitCreds(gitCredsStore), plugin) - log.WithFields(map[string]interface{}{ - "application": q.AppName, - "plugin": q.ApplicationSource.Plugin.Name, - }).Warnf(common.ConfigMapPluginDeprecationWarning) - } else { - // if the named plugin was not found in argocd-cm try sidecar plugin - pluginName := "" - if q.ApplicationSource.Plugin != nil { - pluginName = q.ApplicationSource.Plugin.Name - } - // if pluginName is provided it has to be `-` or just `` if plugin version is empty - targetObjs, err = runConfigManagementPluginSidecars(ctx, appPath, repoRoot, pluginName, env, q, q.Repo.GetGitCreds(gitCredsStore), opt.cmpTarDoneCh, opt.cmpTarExcludedGlobs) - if err != nil { - err = fmt.Errorf("plugin sidecar failed. %s", err.Error()) - } + // if pluginName is provided it has to be `-` or just `` if plugin version is empty + targetObjs, err = runConfigManagementPluginSidecars(ctx, appPath, repoRoot, pluginName, env, q, opt.cmpTarDoneCh, opt.cmpTarExcludedGlobs) + if err != nil { + err = fmt.Errorf("plugin sidecar failed. %s", err.Error()) } case v1alpha1.ApplicationSourceTypeDirectory: var directory *v1alpha1.ApplicationSourceDirectory @@ -1314,7 +1446,7 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string, if q.AppLabelKey != "" && q.AppName != "" && !kube.IsCRD(target) { err = resourceTracking.SetAppInstance(target, q.AppLabelKey, q.AppName, q.Namespace, v1alpha1.TrackingMethod(q.TrackingMethod)) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to set app instance tracking info on manifest: %w", err) } } manifestStr, err := json.Marshal(target.Object) @@ -1325,28 +1457,38 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string, } } - res := apiclient.ManifestResponse{ + return &apiclient.ManifestResponse{ Manifests: manifests, SourceType: string(appSourceType), - } - if dest != nil { - res.Namespace = dest.Namespace - res.Server = dest.Server - } - return &res, nil + }, nil } func newEnv(q *apiclient.ManifestRequest, revision string) *v1alpha1.Env { + shortRevision := revision + if len(shortRevision) > 7 { + shortRevision = shortRevision[:7] + } return &v1alpha1.Env{ &v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: q.AppName}, &v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAMESPACE", Value: q.Namespace}, &v1alpha1.EnvEntry{Name: "ARGOCD_APP_REVISION", Value: revision}, + &v1alpha1.EnvEntry{Name: "ARGOCD_APP_REVISION_SHORT", Value: shortRevision}, &v1alpha1.EnvEntry{Name: "ARGOCD_APP_SOURCE_REPO_URL", Value: q.Repo.Repo}, &v1alpha1.EnvEntry{Name: "ARGOCD_APP_SOURCE_PATH", Value: q.ApplicationSource.Path}, &v1alpha1.EnvEntry{Name: "ARGOCD_APP_SOURCE_TARGET_REVISION", Value: q.ApplicationSource.TargetRevision}, } } +func newEnvRepoQuery(q *apiclient.RepoServerAppDetailsQuery, revision string) *v1alpha1.Env { + return &v1alpha1.Env{ + &v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: q.AppName}, + &v1alpha1.EnvEntry{Name: "ARGOCD_APP_REVISION", Value: revision}, + &v1alpha1.EnvEntry{Name: "ARGOCD_APP_SOURCE_REPO_URL", Value: q.Repo.Repo}, + &v1alpha1.EnvEntry{Name: "ARGOCD_APP_SOURCE_PATH", Value: q.Source.Path}, + &v1alpha1.EnvEntry{Name: "ARGOCD_APP_SOURCE_TARGET_REVISION", Value: q.Source.TargetRevision}, + } +} + // mergeSourceParameters merges parameter overrides from one or more files in // the Git repo into the given ApplicationSource objects. // @@ -1406,8 +1548,8 @@ func mergeSourceParameters(source *v1alpha1.ApplicationSource, path, appName str } // GetAppSourceType returns explicit application source type or examines a directory and determines its application source type -func GetAppSourceType(ctx context.Context, source *v1alpha1.ApplicationSource, path, appName string, enableGenerateManifests map[string]bool, tarExcludedGlobs []string) (v1alpha1.ApplicationSourceType, error) { - err := mergeSourceParameters(source, path, appName) +func GetAppSourceType(ctx context.Context, source *v1alpha1.ApplicationSource, appPath, repoPath, appName string, enableGenerateManifests map[string]bool, tarExcludedGlobs []string, env []string) (v1alpha1.ApplicationSourceType, error) { + err := mergeSourceParameters(source, appPath, appName) if err != nil { return "", fmt.Errorf("error while parsing source parameters: %v", err) } @@ -1423,9 +1565,9 @@ func GetAppSourceType(ctx context.Context, source *v1alpha1.ApplicationSource, p } return *appSourceType, nil } - appType, err := discovery.AppType(ctx, path, enableGenerateManifests, tarExcludedGlobs) + appType, err := discovery.AppType(ctx, appPath, repoPath, enableGenerateManifests, tarExcludedGlobs, env) if err != nil { - return "", err + return "", fmt.Errorf("error getting app source type: %v", err) } return v1alpha1.ApplicationSourceType(appType), nil } @@ -1733,82 +1875,17 @@ func makeJsonnetVm(appPath string, repoRoot string, sourceJsonnet v1alpha1.Appli return vm, nil } -func runCommand(command v1alpha1.Command, path string, env []string) (string, error) { - if len(command.Command) == 0 { - return "", fmt.Errorf("Command is empty") - } - cmd := exec.Command(command.Command[0], append(command.Command[1:], command.Args...)...) - cmd.Env = env - cmd.Dir = path - return executil.Run(cmd) -} - -func findPlugin(plugins []*v1alpha1.ConfigManagementPlugin, name string) *v1alpha1.ConfigManagementPlugin { - for _, plugin := range plugins { - if plugin.Name == name { - return plugin - } - } - return nil -} - -func runConfigManagementPlugin(appPath, repoRoot string, envVars *v1alpha1.Env, q *apiclient.ManifestRequest, creds git.Creds, plugin *v1alpha1.ConfigManagementPlugin) ([]*unstructured.Unstructured, error) { - // Plugins can request to lock the complete repository when they need to - // use git client operations. - if plugin.LockRepo { - manifestGenerateLock.Lock(repoRoot) - defer manifestGenerateLock.Unlock(repoRoot) - } else { - concurrencyAllowed := isConcurrencyAllowed(appPath) - if !concurrencyAllowed { - manifestGenerateLock.Lock(appPath) - defer manifestGenerateLock.Unlock(appPath) - } - } - - env, err := getPluginEnvs(envVars, q, creds, false) - if err != nil { - return nil, err - } - - if plugin.Init != nil { - _, err := runCommand(*plugin.Init, appPath, env) - if err != nil { - return nil, err - } - } - out, err := runCommand(plugin.Generate, appPath, env) - if err != nil { - return nil, err - } - return kube.SplitYAML([]byte(out)) -} - -func getPluginEnvs(env *v1alpha1.Env, q *apiclient.ManifestRequest, creds git.Creds, remote bool) ([]string, error) { +func getPluginEnvs(env *v1alpha1.Env, q *apiclient.ManifestRequest) ([]string, error) { envVars := env.Environ() envVars = append(envVars, "KUBE_VERSION="+text.SemVer(q.KubeVersion)) envVars = append(envVars, "KUBE_API_VERSIONS="+strings.Join(q.ApiVersions, ",")) - return getPluginParamEnvs(envVars, q.ApplicationSource.Plugin, creds, remote) + return getPluginParamEnvs(envVars, q.ApplicationSource.Plugin) } // getPluginParamEnvs gets environment variables for plugin parameter announcement generation. -func getPluginParamEnvs(envVars []string, plugin *v1alpha1.ApplicationSourcePlugin, creds git.Creds, remote bool) ([]string, error) { +func getPluginParamEnvs(envVars []string, plugin *v1alpha1.ApplicationSourcePlugin) ([]string, error) { env := envVars - // Local plugins need also to have access to the local environment variables. - // Remote sidecar plugins will use the environment in the sidecar - // container. - if !remote { - env = append(os.Environ(), envVars...) - } - if creds != nil { - closer, environ, err := creds.Environ() - if err != nil { - return nil, err - } - defer func() { _ = closer.Close() }() - env = append(env, environ...) - } parsedEnv := make(v1alpha1.Env, len(env)) for i, v := range env { @@ -1835,15 +1912,15 @@ func getPluginParamEnvs(envVars []string, plugin *v1alpha1.ApplicationSourcePlug return env, nil } -func runConfigManagementPluginSidecars(ctx context.Context, appPath, repoPath, pluginName string, envVars *v1alpha1.Env, q *apiclient.ManifestRequest, creds git.Creds, tarDoneCh chan<- bool, tarExcludedGlobs []string) ([]*unstructured.Unstructured, error) { +func runConfigManagementPluginSidecars(ctx context.Context, appPath, repoPath, pluginName string, envVars *v1alpha1.Env, q *apiclient.ManifestRequest, tarDoneCh chan<- bool, tarExcludedGlobs []string) ([]*unstructured.Unstructured, error) { // compute variables. - env, err := getPluginEnvs(envVars, q, creds, true) + env, err := getPluginEnvs(envVars, q) if err != nil { return nil, err } - // detect config management plugin server (sidecar) - conn, cmpClient, err := discovery.DetectConfigManagementPlugin(ctx, appPath, pluginName, env, tarExcludedGlobs) + // detect config management plugin server + conn, cmpClient, err := discovery.DetectConfigManagementPlugin(ctx, appPath, repoPath, pluginName, env, tarExcludedGlobs) if err != nil { return nil, err } @@ -1900,7 +1977,9 @@ func (s *Service) GetAppDetails(ctx context.Context, q *apiclient.RepoServerAppD return err } - appSourceType, err := GetAppSourceType(ctx, q.Source, opContext.appPath, q.AppName, q.EnabledSourceTypes, s.initConstants.CMPTarExcludedGlobs) + env := newEnvRepoQuery(q, revision) + + appSourceType, err := GetAppSourceType(ctx, q.Source, opContext.appPath, repoRoot, q.AppName, q.EnabledSourceTypes, s.initConstants.CMPTarExcludedGlobs, env.Environ()) if err != nil { return err } @@ -1913,7 +1992,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: @@ -1921,25 +2000,25 @@ func (s *Service) GetAppDetails(ctx context.Context, q *apiclient.RepoServerAppD return fmt.Errorf("failed to populate plugin app details: %w", err) } } - _ = s.cache.SetAppDetails(revision, q.Source, q.RefSources, res, v1alpha1.TrackingMethod(q.TrackingMethod)) + _ = s.cache.SetAppDetails(revision, q.Source, q.RefSources, res, v1alpha1.TrackingMethod(q.TrackingMethod), nil) return nil } settings := operationSettings{allowConcurrent: q.Source.AllowsConcurrentProcessing(), noCache: q.NoCache, noRevisionCache: q.NoCache || q.NoRevisionCache} - err := s.runRepoOperation(ctx, q.Source.TargetRevision, q.Repo, q.Source, false, cacheFn, operation, settings, false) + err := s.runRepoOperation(ctx, q.Source.TargetRevision, q.Repo, q.Source, false, cacheFn, operation, settings, false, nil) return res, err } -func (s *Service) createGetAppDetailsCacheHandler(res *apiclient.RepoAppDetailsResponse, q *apiclient.RepoServerAppDetailsQuery) func(revision string, _ bool) (bool, error) { - return func(revision string, _ bool) (bool, error) { - err := s.cache.GetAppDetails(revision, q.Source, q.RefSources, res, v1alpha1.TrackingMethod(q.TrackingMethod)) +func (s *Service) createGetAppDetailsCacheHandler(res *apiclient.RepoAppDetailsResponse, q *apiclient.RepoServerAppDetailsQuery) func(revision string, _ cache.ResolvedRevisions, _ bool) (bool, error) { + return func(revision string, _ cache.ResolvedRevisions, _ bool) (bool, error) { + err := s.cache.GetAppDetails(revision, q.Source, q.RefSources, res, v1alpha1.TrackingMethod(q.TrackingMethod), nil) if err == nil { log.Infof("app details cache hit: %s/%s", revision, q.Source.Path) return true, nil } - if err != reposervercache.ErrCacheMiss { + if err != cache.ErrCacheMiss { log.Warnf("app details cache error %s: %v", revision, q.Source) } else { log.Infof("app details cache miss: %s/%s", revision, q.Source) @@ -1950,12 +2029,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 } @@ -1969,7 +2049,11 @@ func populateHelmAppDetails(res *apiclient.RepoAppDetailsResponse, appPath strin } passCredentials = q.Source.Helm.PassCredentials } - h, err := helm.NewHelmApp(appPath, getHelmRepos(q.Repos), false, version, q.Repo.Proxy, passCredentials) + helmRepos, err := getHelmRepos(appPath, q.Repos, nil) + if err != nil { + return err + } + h, err := helm.NewHelmApp(appPath, helmRepos, false, version, q.Repo.Proxy, passCredentials) if err != nil { return err } @@ -2007,7 +2091,7 @@ func populateHelmAppDetails(res *apiclient.RepoAppDetailsResponse, appPath strin for _, v := range fileParameters(q) { res.Helm.FileParameters = append(res.Helm.FileParameters, &v1alpha1.HelmFileParameter{ Name: v.Name, - Path: v.Path, //filepath.Join(appPath, v.Path), + Path: v.Path, // filepath.Join(appPath, v.Path), }) } return nil @@ -2020,7 +2104,7 @@ func loadFileIntoIfExists(path pathutil.ResolvedFilePath, destination *string) e if err == nil && !info.IsDir() { bytes, err := os.ReadFile(stringPath) if err != nil { - return err + return fmt.Errorf("error reading file from %s: %w", stringPath, err) } *destination = string(bytes) } @@ -2028,35 +2112,34 @@ func loadFileIntoIfExists(path pathutil.ResolvedFilePath, destination *string) e return nil } -func findHelmValueFilesInPath(path string) ([]string, error) { - var result []string - - files, err := os.ReadDir(path) - if err != nil { - return result, err - } +func walkHelmValueFilesInPath(root string, valueFiles *[]string) filepath.WalkFunc { + return func(path string, info os.FileInfo, err error) error { - 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 @@ -2075,8 +2158,6 @@ func populateKustomizeAppDetails(res *apiclient.RepoAppDetailsResponse, q *apicl func populatePluginAppDetails(ctx context.Context, res *apiclient.RepoAppDetailsResponse, appPath string, repoPath string, q *apiclient.RepoServerAppDetailsQuery, store git.CredsStore, tarExcludedGlobs []string) error { res.Plugin = &apiclient.PluginAppSpec{} - creds := q.Repo.GetGitCreds(store) - envVars := []string{ fmt.Sprintf("ARGOCD_APP_NAME=%s", q.AppName), fmt.Sprintf("ARGOCD_APP_SOURCE_REPO_URL=%s", q.Repo.Repo), @@ -2084,7 +2165,7 @@ func populatePluginAppDetails(ctx context.Context, res *apiclient.RepoAppDetails fmt.Sprintf("ARGOCD_APP_SOURCE_TARGET_REVISION=%s", q.Source.TargetRevision), } - env, err := getPluginParamEnvs(envVars, q.Source.Plugin, creds, true) + env, err := getPluginParamEnvs(envVars, q.Source.Plugin) if err != nil { return fmt.Errorf("failed to get env vars for plugin: %w", err) } @@ -2094,23 +2175,23 @@ func populatePluginAppDetails(ctx context.Context, res *apiclient.RepoAppDetails pluginName = q.Source.Plugin.Name } // detect config management plugin server (sidecar) - conn, cmpClient, err := discovery.DetectConfigManagementPlugin(ctx, appPath, pluginName, env, tarExcludedGlobs) + conn, cmpClient, err := discovery.DetectConfigManagementPlugin(ctx, appPath, repoPath, pluginName, env, tarExcludedGlobs) if err != nil { return fmt.Errorf("failed to detect CMP for app: %w", err) } defer io.Close(conn) - generateManifestStream, err := cmpClient.GetParametersAnnouncement(ctx, grpc_retry.Disable()) + parametersAnnouncementStream, err := cmpClient.GetParametersAnnouncement(ctx, grpc_retry.Disable()) if err != nil { - return fmt.Errorf("error getting generateManifestStream: %w", err) + return fmt.Errorf("error getting parametersAnnouncementStream: %w", err) } - err = cmp.SendRepoStream(generateManifestStream.Context(), appPath, repoPath, generateManifestStream, env, tarExcludedGlobs) + err = cmp.SendRepoStream(parametersAnnouncementStream.Context(), appPath, repoPath, parametersAnnouncementStream, env, tarExcludedGlobs) if err != nil { return fmt.Errorf("error sending file to cmp-server: %s", err) } - announcement, err := generateManifestStream.CloseAndRecv() + announcement, err := parametersAnnouncementStream.CloseAndRecv() if err != nil { return fmt.Errorf("failed to get parameter anouncement: %w", err) } @@ -2142,7 +2223,7 @@ func (s *Service) GetRevisionMetadata(ctx context.Context, q *apiclient.RepoServ return metadata, nil } } else { - if err != reposervercache.ErrCacheMiss { + if err != cache.ErrCacheMiss { log.Warnf("revision metadata cache error %s/%s: %v", q.Repo.Repo, q.Revision, err) } else { log.Infof("revision metadata cache miss: %s/%s", q.Repo.Repo, q.Revision) @@ -2162,7 +2243,7 @@ func (s *Service) GetRevisionMetadata(ctx context.Context, q *apiclient.RepoServ }) if err != nil { - return nil, err + return nil, fmt.Errorf("error acquiring repo lock: %w", err) } defer io.Close(closer) @@ -2198,6 +2279,45 @@ func (s *Service) GetRevisionMetadata(ctx context.Context, q *apiclient.RepoServ return metadata, nil } +// GetRevisionChartDetails returns the helm chart details of a given version +func (s *Service) GetRevisionChartDetails(ctx context.Context, q *apiclient.RepoServerRevisionChartDetailsRequest) (*v1alpha1.ChartDetails, error) { + details, err := s.cache.GetRevisionChartDetails(q.Repo.Repo, q.Name, q.Revision) + if err == nil { + log.Infof("revision chart details cache hit: %s/%s/%s", q.Repo.Repo, q.Name, q.Revision) + return details, nil + } else { + if err == cache.ErrCacheMiss { + log.Infof("revision metadata cache miss: %s/%s/%s", q.Repo.Repo, q.Name, q.Revision) + } else { + log.Warnf("revision metadata cache error %s/%s/%s: %v", q.Repo.Repo, q.Name, q.Revision, err) + } + } + helmClient, revision, err := s.newHelmClientResolveRevision(q.Repo, q.Revision, q.Name, true) + if err != nil { + return nil, fmt.Errorf("helm client error: %v", err) + } + chartPath, closer, err := helmClient.ExtractChart(q.Name, revision, false, s.initConstants.HelmManifestMaxExtractedSize, s.initConstants.DisableHelmManifestMaxExtractedSize) + if err != nil { + return nil, fmt.Errorf("error extracting chart: %v", err) + } + defer io.Close(closer) + helmCmd, err := helm.NewCmdWithVersion(chartPath, helm.HelmV3, q.Repo.EnableOCI, q.Repo.Proxy) + if err != nil { + return nil, fmt.Errorf("error creating helm cmd: %v", err) + } + defer helmCmd.Close() + helmDetails, err := helmCmd.InspectChart() + if err != nil { + return nil, fmt.Errorf("error inspecting chart: %v", err) + } + details, err = getChartDetails(helmDetails) + if err != nil { + return nil, fmt.Errorf("error getting chart details: %v", err) + } + _ = s.cache.SetRevisionChartDetails(q.Repo.Repo, q.Name, q.Revision, details) + return details, nil +} + func fileParameters(q *apiclient.RepoServerAppDetailsQuery) []v1alpha1.HelmFileParameter { if q.Source.Helm == nil { return nil @@ -2252,7 +2372,7 @@ func (s *Service) newHelmClientResolveRevision(repo *v1alpha1.Repository, revisi return helmClient, version.String(), nil } - index, err := helmClient.GetIndex(noRevisionCache) + index, err := helmClient.GetIndex(noRevisionCache, s.initConstants.HelmRegistryMaxIndexSize) if err != nil { return nil, "", err } @@ -2293,7 +2413,11 @@ func directoryPermissionInitializer(rootPath string) goio.Closer { // nolint:unparam func (s *Service) checkoutRevision(gitClient git.Client, revision string, submoduleEnabled bool) (goio.Closer, error) { closer := s.gitRepoInitializer(gitClient.Root()) - return closer, checkoutRevision(gitClient, revision, submoduleEnabled) + err := checkoutRevision(gitClient, revision, submoduleEnabled) + if err != nil { + s.metricsServer.IncGitFetchFail(gitClient.Root(), revision) + } + return closer, err } func checkoutRevision(gitClient git.Client, revision string, submoduleEnabled bool) error { @@ -2330,7 +2454,7 @@ func checkoutRevision(gitClient git.Client, revision string, submoduleEnabled bo } func (s *Service) GetHelmCharts(ctx context.Context, q *apiclient.HelmChartsRequest) (*apiclient.HelmChartsResponse, error) { - index, err := s.newHelmClient(q.Repo.Repo, q.Repo.GetHelmCreds(), q.Repo.EnableOCI, q.Repo.Proxy, helm.WithChartPaths(s.chartPaths)).GetIndex(true) + index, err := s.newHelmClient(q.Repo.Repo, q.Repo.GetHelmCreds(), q.Repo.EnableOCI, q.Repo.Proxy, helm.WithChartPaths(s.chartPaths)).GetIndex(true, s.initConstants.HelmRegistryMaxIndexSize) if err != nil { return nil, err } @@ -2365,7 +2489,7 @@ func (s *Service) TestRepository(ctx context.Context, q *apiclient.TestRepositor _, err := helm.NewClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI, repo.Proxy).TestHelmOCI() return err } else { - _, err := helm.NewClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI, repo.Proxy).GetIndex(false) + _, err := helm.NewClient(repo.Repo, repo.GetHelmCreds(), repo.EnableOCI, repo.Proxy).GetIndex(false, s.initConstants.HelmRegistryMaxIndexSize) return err } }, @@ -2412,3 +2536,142 @@ func (s *Service) ResolveRevision(ctx context.Context, q *apiclient.ResolveRevis }, nil } } + +func (s *Service) GetGitFiles(_ context.Context, request *apiclient.GitFilesRequest) (*apiclient.GitFilesResponse, error) { + repo := request.GetRepo() + revision := request.GetRevision() + gitPath := request.GetPath() + noRevisionCache := request.GetNoRevisionCache() + enableNewGitFileGlobbing := request.GetNewGitFileGlobbingEnabled() + if gitPath == "" { + gitPath = "." + } + + 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, !noRevisionCache)) + if err != nil { + return nil, status.Errorf(codes.Internal, "unable to resolve git revision %s: %v", revision, err) + } + + // check the cache and return the results if present + if cachedFiles, err := s.cache.GetGitFiles(repo.Repo, revision, gitPath); err == nil { + log.Debugf("cache hit for repo: %s revision: %s pattern: %s", repo.Repo, revision, gitPath) + return &apiclient.GitFilesResponse{ + Map: cachedFiles, + }, nil + } + + s.metricsServer.IncPendingRepoRequest(repo.Repo) + defer s.metricsServer.DecPendingRepoRequest(repo.Repo) + + // cache miss, generate the results + closer, err := s.repoLock.Lock(gitClient.Root(), revision, true, func() (goio.Closer, error) { + return s.checkoutRevision(gitClient, revision, request.GetSubmoduleEnabled()) + }) + if err != nil { + return nil, status.Errorf(codes.Internal, "unable to checkout git repo %s with revision %s pattern %s: %v", repo.Repo, revision, gitPath, err) + } + defer io.Close(closer) + + gitFiles, err := gitClient.LsFiles(gitPath, enableNewGitFileGlobbing) + if err != nil { + return nil, status.Errorf(codes.Internal, "unable to list files. repo %s with revision %s pattern %s: %v", repo.Repo, revision, gitPath, err) + } + log.Debugf("listed %d git files from %s under %s", len(gitFiles), repo.Repo, gitPath) + + res := make(map[string][]byte) + for _, filePath := range gitFiles { + fileContents, err := os.ReadFile(filepath.Join(gitClient.Root(), filePath)) + if err != nil { + return nil, status.Errorf(codes.Internal, "unable to read files. repo %s with revision %s pattern %s: %v", repo.Repo, revision, gitPath, err) + } + res[filePath] = fileContents + } + + err = s.cache.SetGitFiles(repo.Repo, revision, gitPath, res) + if err != nil { + log.Warnf("error caching git files for repo %s with revision %s pattern %s: %v", repo.Repo, revision, gitPath, err) + } + + return &apiclient.GitFilesResponse{ + Map: res, + }, nil +} + +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, !noRevisionCache)) + if err != nil { + return nil, status.Errorf(codes.Internal, "unable to resolve git revision %s: %v", revision, err) + } + + // check the cache and return the results if present + if cachedPaths, err := s.cache.GetGitDirectories(repo.Repo, revision); err == nil { + log.Debugf("cache hit for repo: %s revision: %s", repo.Repo, revision) + return &apiclient.GitDirectoriesResponse{ + Paths: cachedPaths, + }, nil + } + + s.metricsServer.IncPendingRepoRequest(repo.Repo) + defer s.metricsServer.DecPendingRepoRequest(repo.Repo) + + // cache miss, generate the results + closer, err := s.repoLock.Lock(gitClient.Root(), revision, true, func() (goio.Closer, error) { + return s.checkoutRevision(gitClient, revision, request.GetSubmoduleEnabled()) + }) + if err != nil { + return nil, status.Errorf(codes.Internal, "unable to checkout git repo %s with revision %s: %v", repo.Repo, revision, err) + } + defer io.Close(closer) + + repoRoot := gitClient.Root() + var paths []string + if err := filepath.WalkDir(repoRoot, func(path string, entry fs.DirEntry, fnErr error) error { + if fnErr != nil { + return fmt.Errorf("error walking the file tree: %w", fnErr) + } + if !entry.IsDir() { // Skip files: directories only + return nil + } + + fname := entry.Name() + if strings.HasPrefix(fname, ".") { // Skip all folders starts with "." + return filepath.SkipDir + } + + relativePath, err := filepath.Rel(repoRoot, path) + if err != nil { + return fmt.Errorf("error constructing relative repo path: %w", err) + } + + if relativePath == "." { // Exclude '.' from results + return nil + } + + paths = append(paths, relativePath) + + return nil + }); err != nil { + return nil, err + } + + log.Debugf("found %d git paths from %s", len(paths), repo.Repo) + err = s.cache.SetGitDirectories(repo.Repo, revision, paths) + if err != nil { + log.Warnf("error caching git directories for repo %s with revision %s: %v", repo.Repo, revision, err) + } + + return &apiclient.GitDirectoriesResponse{ + Paths: paths, + }, nil +} diff --git a/reposerver/repository/repository.proto b/reposerver/repository/repository.proto index c5212265d33b7..de061122e2586 100644 --- a/reposerver/repository/repository.proto +++ b/reposerver/repository/repository.proto @@ -18,6 +18,7 @@ message ManifestRequest { string namespace = 8; github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSource applicationSource = 10; repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repos = 11; + // Deprecated: use sidecar plugins instead. repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ConfigManagementPlugin plugins = 12; github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.KustomizeOptions kustomizeOptions = 13; string kubeVersion = 14; @@ -31,6 +32,10 @@ message ManifestRequest { github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.HelmOptions helmOptions = 21; bool hasMultipleSources = 22; map refSources = 23; + // This is used to surface "source not permitted" errors for Helm repositories + repeated string projectSourceRepos = 24; + // This is used to surface "source not permitted" errors for Helm repositories + string projectName = 25; } message ManifestRequestWithFiles { @@ -89,13 +94,13 @@ message ManifestResponse { } message ListRefsRequest { - github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repo = 1; + github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repo = 1; } // A subset of the repository's named refs message Refs { - repeated string branches = 1; - repeated string tags = 2; + repeated string branches = 1; + repeated string tags = 2; } // ListAppsRequest requests a repository directory structure @@ -136,11 +141,11 @@ message RepoServerAppDetailsQuery { // RepoAppDetailsResponse application details message RepoAppDetailsResponse { - string type = 1; - HelmAppSpec helm = 3; - KustomizeAppSpec kustomize = 4; - DirectoryAppSpec directory = 5; - PluginAppSpec plugin = 6; + string type = 1; + HelmAppSpec helm = 3; + KustomizeAppSpec kustomize = 4; + DirectoryAppSpec directory = 5; + PluginAppSpec plugin = 6; } message RepoServerRevisionMetadataRequest { @@ -152,22 +157,31 @@ message RepoServerRevisionMetadataRequest { bool checkSignature = 3; } +message RepoServerRevisionChartDetailsRequest { + // the repo + github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repo = 1; + // the chart + string name = 2; + // the revision within the chart + string revision = 3; +} + // HelmAppSpec contains helm app name in source repo message HelmAppSpec { - string name = 1; - repeated string valueFiles = 3; - // the output of `helm inspect values` - repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.HelmParameter parameters = 4; - // the contents of values.yaml - string values = 5; + string name = 1; + repeated string valueFiles = 3; + // the output of `helm inspect values` + repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.HelmParameter parameters = 4; + // the contents of values.yaml + string values = 5; // helm file parameters repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.HelmFileParameter fileParameters = 6; } // KustomizeAppSpec contains kustomize images message KustomizeAppSpec { - // images is a list of available images. - repeated string images = 3; + // images is a list of available images. + repeated string images = 3; } // DirectoryAppSpec contains directory @@ -216,6 +230,32 @@ message HelmChartsResponse { repeated HelmChart items = 1; } +message GitFilesRequest { + github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repo = 1; + bool submoduleEnabled = 2; + string revision = 3; + string path = 4; + bool NewGitFileGlobbingEnabled = 5; + bool noRevisionCache = 6; +} + +message GitFilesResponse { + // Map consisting of path of the path to its contents in bytes + map map = 1; +} + +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 { + // A set of directory paths + repeated string paths = 1; +} + // ManifestService service RepoServerService { @@ -234,7 +274,7 @@ service RepoServerService { // Returns a valid revision rpc ResolveRevision(ResolveRevisionRequest) returns (ResolveRevisionResponse) { } - + // Returns a list of refs (e.g. branches and tags) in the repo rpc ListRefs(ListRefsRequest) returns (Refs) { } @@ -254,8 +294,20 @@ service RepoServerService { // Get the meta-data (author, date, tags, message) for a specific revision of the repo rpc GetRevisionMetadata(RepoServerRevisionMetadataRequest) returns (github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.RevisionMetadata) { } + + // Get the chart details (author, date, tags, message) for a specific revision of the repo + rpc GetRevisionChartDetails(RepoServerRevisionChartDetailsRequest) returns (github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ChartDetails) { + } // GetHelmCharts returns list of helm charts in the specified repository rpc GetHelmCharts(HelmChartsRequest) returns (HelmChartsResponse) { } + + // GetGitFiles returns a set of file paths and their contents for the given repo + rpc GetGitFiles(GitFilesRequest) returns (GitFilesResponse) { + } + + // GetGitDirectories returns a set of directory paths for the given repo + rpc GetGitDirectories(GitDirectoriesRequest) returns (GitDirectoriesResponse) { + } } diff --git a/reposerver/repository/repository_test.go b/reposerver/repository/repository_test.go index d8f1df05f44c3..d48f50a832eb0 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" @@ -14,27 +15,31 @@ import ( "regexp" "sort" "strings" + "sync" "testing" "time" + cacheutil "github.com/argoproj/argo-cd/v2/util/cache" log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/api/resource" - "github.com/ghodss/yaml" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" v1 "k8s.io/api/apps/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/yaml" + "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/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,18 +56,60 @@ 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 { + return newCacheMocksWithOpts(1*time.Minute, 1*time.Minute, 10*time.Second) +} + +func newCacheMocksWithOpts(repoCacheExpiration, revisionCacheExpiration, revisionCacheLockTimeout time.Duration) *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, repoCacheExpiration, revisionCacheExpiration, revisionCacheLockTimeout), + 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) gitClient.On("LsRemote", mock.Anything).Return(mock.Anything, nil) gitClient.On("CommitSHA").Return(mock.Anything, nil) gitClient.On("Root").Return(root) + gitClient.On("IsAnnotatedTag").Return(false) if signed { gitClient.On("VerifyCommitSignature", mock.Anything).Return(testSignature, nil) } else { @@ -72,7 +119,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"), mock.Anything).Return(&helm.Index{Entries: map[string]helm.Entries{ chart: {{Version: "1.0.0"}, {Version: version}}, oobChart: {{Version: "1.0.0"}, {Version: version}}, }}, nil) @@ -88,18 +135,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 { @@ -109,20 +154,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}$") @@ -130,7 +175,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) @@ -149,13 +194,18 @@ 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{Repo: &argoappv1.Repository{}, ApplicationSource: &src} + q := apiclient.ManifestRequest{ + Repo: &argoappv1.Repository{}, + ApplicationSource: &src, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, + } // update this value if we add/remove manifests - const countOfManifests = 49 + const countOfManifests = 48 res1, err := service.GenerateManifest(context.Background(), &q) @@ -218,7 +268,8 @@ func Test_GenerateManifests_NoOutOfBoundsAccess(t *testing.T) { mustNotContain = testCaseCopy.mustNotContain } - q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &argoappv1.ApplicationSource{}} + q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &argoappv1.ApplicationSource{}, ProjectName: "something", + ProjectSourceRepos: []string{"*"}} res, err := GenerateManifests(context.Background(), repoDir, "", "", &q, false, &git.NoopCredsStore{}, resource.MustParse("0"), nil) require.Error(t, err) assert.NotContains(t, err.Error(), mustNotContain) @@ -233,23 +284,27 @@ func TestGenerateManifests_MissingSymlinkDestination(t *testing.T) { err := os.Symlink("/obviously/does/not/exist", path.Join(repoDir, "test.yaml")) require.NoError(t, err) - q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &argoappv1.ApplicationSource{}} + q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &argoappv1.ApplicationSource{}, ProjectName: "something", + ProjectSourceRepos: []string{"*"}} _, err = GenerateManifests(context.Background(), repoDir, "", "", &q, false, &git.NoopCredsStore{}, resource.MustParse("0"), nil) require.NoError(t, err) } func TestGenerateManifests_K8SAPIResetCache(t *testing.T) { - service := newService("../../manifests/base") + service := newService(t, "../../manifests/base") src := argoappv1.ApplicationSource{Path: "."} q := apiclient.ManifestRequest{ - KubeVersion: "v1.16.0", - Repo: &argoappv1.Repository{}, ApplicationSource: &src, + KubeVersion: "v1.16.0", + Repo: &argoappv1.Repository{}, + ApplicationSource: &src, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, } cachedFakeResponse := &apiclient.ManifestResponse{Manifests: []string{"Fake"}} - err := service.cache.SetManifests(mock.Anything, &src, q.RefSources, &q, "", "", "", "", &cache.CachedManifestResponse{ManifestResponse: cachedFakeResponse}) + err := service.cache.SetManifests(mock.Anything, &src, q.RefSources, &q, "", "", "", "", &cache.CachedManifestResponse{ManifestResponse: cachedFakeResponse}, nil) assert.NoError(t, err) res, err := service.GenerateManifest(context.Background(), &q) @@ -264,26 +319,160 @@ 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{ - Repo: &argoappv1.Repository{}, ApplicationSource: &src, + Repo: &argoappv1.Repository{}, + ApplicationSource: &src, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, } - err := service.cache.SetManifests(mock.Anything, &src, q.RefSources, &q, "", "", "", "", &cache.CachedManifestResponse{ManifestResponse: nil}) + err := service.cache.SetManifests(mock.Anything, &src, q.RefSources, &q, "", "", "", "", &cache.CachedManifestResponse{ManifestResponse: nil}, nil) assert.NoError(t, err) 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: 2, + ExternalGets: 2}) + 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}}, nil) + 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} + request := &apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: source, NoCache: true, ProjectName: "something", + ProjectSourceRepos: []string{"*"}} response, err := service.GenerateManifest(context.Background(), request) assert.NoError(t, err) assert.NotNil(t, response) @@ -294,10 +483,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{ @@ -312,7 +505,8 @@ func TestHelmChartReferencingExternalValues(t *testing.T) { }, nil) refSources, err := argo.GetRefSources(context.Background(), spec, repoDB) require.NoError(t, err) - request := &apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &spec.Sources[0], NoCache: true, RefSources: refSources, HasMultipleSources: true} + request := &apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &spec.Sources[0], NoCache: true, RefSources: refSources, HasMultipleSources: true, ProjectName: "something", + ProjectSourceRepos: []string{"*"}} response, err := service.GenerateManifest(context.Background(), request) assert.NoError(t, err) assert.NotNil(t, response) @@ -326,7 +520,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() { @@ -360,11 +554,12 @@ 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}} - q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, Revision: "abc"} + q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, Revision: "abc", ProjectName: "something", + ProjectSourceRepos: []string{"*"}} res1, err := service.GenerateManifest(context.Background(), &q) assert.Nil(t, err) @@ -373,11 +568,12 @@ 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}} - q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src} + q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, ProjectName: "something", + ProjectSourceRepos: []string{"*"}} res1, err := service.GenerateManifest(context.Background(), &q) assert.Nil(t, err) @@ -385,7 +581,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}} @@ -395,8 +591,30 @@ func TestInvalidManifestsInDir(t *testing.T) { assert.NotNil(t, err) } +func TestInvalidMetadata(t *testing.T) { + 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"} + _, err := service.GenerateManifest(context.Background(), &q) + assert.Error(t, err) + assert.Contains(t, err.Error(), "contains non-string key in the map") +} + +func TestNilMetadataAccessors(t *testing.T) { + 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}} + q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, AppLabelKey: "test", AppName: "nil-metadata-accessors", TrackingMethod: "annotation+label"} + res, err := service.GenerateManifest(context.Background(), &q) + assert.NoError(t, err) + assert.Equal(t, len(res.Manifests), 1) + assert.Equal(t, expected, res.Manifests[0]) +} + func TestGenerateJsonnetManifestInDir(t *testing.T) { - service := newService(".") + service := newService(t, ".") q := apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, @@ -410,6 +628,8 @@ func TestGenerateJsonnetManifestInDir(t *testing.T) { }, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, } res1, err := service.GenerateManifest(context.Background(), &q) assert.Nil(t, err) @@ -417,7 +637,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{}, @@ -431,6 +651,8 @@ func TestGenerateJsonnetManifestInRootDir(t *testing.T) { }, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, } res1, err := service.GenerateManifest(context.Background(), &q) assert.Nil(t, err) @@ -438,7 +660,7 @@ func TestGenerateJsonnetManifestInRootDir(t *testing.T) { } func TestGenerateJsonnetLibOutside(t *testing.T) { - service := newService(".") + service := newService(t, ".") q := apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, @@ -450,6 +672,8 @@ func TestGenerateJsonnetLibOutside(t *testing.T) { }, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, } _, err := service.GenerateManifest(context.Background(), &q) require.Error(t, err) @@ -464,7 +688,7 @@ func TestManifestGenErrorCacheByNumRequests(t *testing.T) { assert.NotNil(t, manifestRequest) cachedManifestResponse := &cache.CachedManifestResponse{} - err := service.cache.GetManifests(mock.Anything, manifestRequest.ApplicationSource, manifestRequest.RefSources, manifestRequest, manifestRequest.Namespace, "", manifestRequest.AppLabelKey, manifestRequest.AppName, cachedManifestResponse) + err := service.cache.GetManifests(mock.Anything, manifestRequest.ApplicationSource, manifestRequest.RefSources, manifestRequest, manifestRequest.Namespace, "", manifestRequest.AppLabelKey, manifestRequest.AppName, cachedManifestResponse, nil) assert.Nil(t, err) return cachedManifestResponse } @@ -507,7 +731,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, @@ -585,7 +809,7 @@ func TestManifestGenErrorCacheFileContentsChange(t *testing.T) { tmpDir := t.TempDir() - service := newService(tmpDir) + service := newService(t, tmpDir) service.initConstants = RepoServerInitConstants{ ParallelismLimit: 1, @@ -624,6 +848,8 @@ func TestManifestGenErrorCacheFileContentsChange(t *testing.T) { ApplicationSource: &argoappv1.ApplicationSource{ Path: ".", }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) fmt.Println("-", step, "-", res != nil, err != nil, errorExpected) @@ -653,7 +879,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() @@ -723,7 +949,7 @@ func TestManifestGenErrorCacheByMinutesElapsed(t *testing.T) { func TestManifestGenErrorCacheRespectsNoCache(t *testing.T) { - service := newService(".") + service := newService(t, ".") service.initConstants = RepoServerInitConstants{ ParallelismLimit: 1, @@ -780,7 +1006,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{}, @@ -788,10 +1014,12 @@ func TestGenerateHelmWithValues(t *testing.T) { ApplicationSource: &argoappv1.ApplicationSource{ Path: ".", Helm: &argoappv1.ApplicationSourceHelm{ - ValueFiles: []string{"values-production.yaml"}, - Values: `cluster: {slaveCount: 2}`, + ValueFiles: []string{"values-production.yaml"}, + ValuesObject: &runtime.RawExtension{Raw: []byte(`cluster: {slaveCount: 2}`)}, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.NoError(t, err) @@ -815,7 +1043,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{ @@ -827,6 +1055,8 @@ func TestHelmWithMissingValueFiles(t *testing.T) { ValueFiles: []string{"values-production.yaml", missingValuesFile}, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, } // Should fail since we're passing a non-existent values file, and error should indicate that @@ -841,7 +1071,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{}, @@ -852,6 +1082,8 @@ func TestGenerateHelmWithEnvVars(t *testing.T) { ValueFiles: []string{"values-$ARGOCD_APP_NAME.yaml"}, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.NoError(t, err) @@ -874,36 +1106,40 @@ 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 sill under the repo directory (`~/go/src/github.com/argoproj/argo-cd`), it is allowed +// 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", ApplicationSource: &argoappv1.ApplicationSource{ Path: "./redis", Helm: &argoappv1.ApplicationSourceHelm{ - ValueFiles: []string{"../minio/values.yaml"}, - Values: `cluster: {slaveCount: 2}`, + ValueFiles: []string{"../minio/values.yaml"}, + ValuesObject: &runtime.RawExtension{Raw: []byte(`cluster: {slaveCount: 2}`)}, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) 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", ApplicationSource: &argoappv1.ApplicationSource{ Path: "./my-chart", }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.NoError(t, err) } 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) @@ -913,7 +1149,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", @@ -921,7 +1157,12 @@ func TestHelmManifestFromChartRepoWithValueFile(t *testing.T) { ValueFiles: []string{"./my-chart-values.yaml"}, }, } - request := &apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: source, NoCache: true} + request := &apiclient.ManifestRequest{ + Repo: &argoappv1.Repository{}, + ApplicationSource: source, + NoCache: true, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}} response, err := service.GenerateManifest(context.Background(), request) assert.NoError(t, err) assert.NotNil(t, response) @@ -937,7 +1178,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", @@ -952,7 +1193,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", @@ -960,14 +1201,15 @@ func TestHelmManifestFromChartRepoWithValueFileLinks(t *testing.T) { ValueFiles: []string{"my-chart-link.yaml"}, }, } - request := &apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: source, NoCache: true} + request := &apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: source, NoCache: true, ProjectName: "something", + ProjectSourceRepos: []string{"*"}} _, err := service.GenerateManifest(context.Background(), request) assert.NoError(t, err) }) } 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{}, @@ -975,11 +1217,13 @@ func TestGenerateHelmWithURL(t *testing.T) { ApplicationSource: &argoappv1.ApplicationSource{ Path: ".", Helm: &argoappv1.ApplicationSourceHelm{ - ValueFiles: []string{"https://raw.githubusercontent.com/argoproj/argocd-example-apps/master/helm-guestbook/values.yaml"}, - Values: `cluster: {slaveCount: 2}`, + ValueFiles: []string{"https://raw.githubusercontent.com/argoproj/argocd-example-apps/master/helm-guestbook/values.yaml"}, + ValuesObject: &runtime.RawExtension{Raw: []byte(`cluster: {slaveCount: 2}`)}, }, }, - HelmOptions: &argoappv1.HelmOptions{ValuesFileSchemes: []string{"https"}}, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, + HelmOptions: &argoappv1.HelmOptions{ValuesFileSchemes: []string{"https"}}, }) assert.NoError(t, err) } @@ -988,90 +1232,100 @@ 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", ApplicationSource: &argoappv1.ApplicationSource{ Path: ".", Helm: &argoappv1.ApplicationSourceHelm{ - ValueFiles: []string{"../minio/values.yaml"}, - Values: `cluster: {slaveCount: 2}`, + ValueFiles: []string{"../minio/values.yaml"}, + ValuesObject: &runtime.RawExtension{Raw: []byte(`cluster: {slaveCount: 2}`)}, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.Error(t, err) assert.Contains(t, err.Error(), "outside repository root") }) 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", ApplicationSource: &argoappv1.ApplicationSource{ Path: "./my-chart", Helm: &argoappv1.ApplicationSourceHelm{ - ValueFiles: []string{"../my-chart/my-chart-values.yaml"}, - Values: `cluster: {slaveCount: 2}`, + ValueFiles: []string{"../my-chart/my-chart-values.yaml"}, + ValuesObject: &runtime.RawExtension{Raw: []byte(`cluster: {slaveCount: 2}`)}, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.NoError(t, err) }) 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", ApplicationSource: &argoappv1.ApplicationSource{ Path: "./my-chart", Helm: &argoappv1.ApplicationSourceHelm{ - ValueFiles: []string{"/my-chart/my-chart-values.yaml"}, - Values: `cluster: {slaveCount: 2}`, + ValueFiles: []string{"/my-chart/my-chart-values.yaml"}, + ValuesObject: &runtime.RawExtension{Raw: []byte(`cluster: {slaveCount: 2}`)}, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.NoError(t, err) }) 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", ApplicationSource: &argoappv1.ApplicationSource{ Path: "./my-chart", Helm: &argoappv1.ApplicationSourceHelm{ - ValueFiles: []string{"/../../../my-chart-values.yaml"}, - Values: `cluster: {slaveCount: 2}`, + ValueFiles: []string{"/../../../my-chart-values.yaml"}, + ValuesObject: &runtime.RawExtension{Raw: []byte(`cluster: {slaveCount: 2}`)}, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.Error(t, err) assert.Contains(t, err.Error(), "outside repository root") }) 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", ApplicationSource: &argoappv1.ApplicationSource{ Path: "./my-chart", Helm: &argoappv1.ApplicationSourceHelm{ - ValueFiles: []string{"file://../../../../my-chart-values.yaml"}, - Values: `cluster: {slaveCount: 2}`, + ValueFiles: []string{"file://../../../../my-chart-values.yaml"}, + ValuesObject: &runtime.RawExtension{Raw: []byte(`cluster: {slaveCount: 2}`)}, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.Error(t, err) assert.Contains(t, err.Error(), "is not allowed") }) 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", @@ -1081,7 +1335,9 @@ func TestGenerateHelmWithValuesDirectoryTraversalOutsideRepo(t *testing.T) { ValueFiles: []string{"s3://my-bucket/my-chart-values.yaml"}, }, }, - HelmOptions: &argoappv1.HelmOptions{ValuesFileSchemes: []string{"s3"}}, + HelmOptions: &argoappv1.HelmOptions{ValuesFileSchemes: []string{"s3"}}, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.Error(t, err) assert.Contains(t, err.Error(), "s3://my-bucket/my-chart-values.yaml: no such file or directory") @@ -1090,7 +1346,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) @@ -1112,53 +1368,59 @@ func TestGenerateHelmWithAbsoluteFileParameter(t *testing.T) { ApplicationSource: &argoappv1.ApplicationSource{ Path: "./util/helm/testdata/redis", Helm: &argoappv1.ApplicationSourceHelm{ - ValueFiles: []string{"values-production.yaml"}, - Values: `cluster: {slaveCount: 2}`, + ValueFiles: []string{"values-production.yaml"}, + ValuesObject: &runtime.RawExtension{Raw: []byte(`cluster: {slaveCount: 2}`)}, FileParameters: []argoappv1.HelmFileParameter{{ Name: "passwordContent", Path: externalSecretPath, }}, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.Error(t, err) } // The requested file parameter (`../external/external-secret.txt`) is outside the app path -// (`./util/helm/testdata/redis`), however since the requested value is sill under the repo +// (`./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. 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") - _, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ + res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, AppName: "test", ApplicationSource: &argoappv1.ApplicationSource{ Path: "./redis", Helm: &argoappv1.ApplicationSourceHelm{ - ValueFiles: []string{"values-production.yaml"}, - Values: `cluster: {slaveCount: 2}`, - FileParameters: []argoappv1.HelmFileParameter{ - argoappv1.HelmFileParameter{ - Name: "passwordContent", - Path: "../external/external-secret.txt", - }, - }, + ValueFiles: []string{"values-production.yaml"}, + Values: `cluster: {slaveCount: 10}`, + ValuesObject: &runtime.RawExtension{Raw: []byte(`cluster: {slaveCount: 2}`)}, + FileParameters: []argoappv1.HelmFileParameter{{ + Name: "passwordContent", + Path: "../external/external-secret.txt", + }}, }, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.NoError(t, err) + assert.Contains(t, res.Manifests[6], `"replicas":2`, "ValuesObject should override Values") } 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{ - Repo: &argoappv1.Repository{}, - ApplicationSource: &argoappv1.ApplicationSource{Path: "./testdata/null-list"}, - NoCache: true, + Repo: &argoappv1.Repository{}, + ApplicationSource: &argoappv1.ApplicationSource{Path: "./testdata/null-list"}, + NoCache: true, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.Nil(t, err) assert.Equal(t, len(res1.Manifests), 1) @@ -1167,9 +1429,11 @@ func TestGenerateNullList(t *testing.T) { t.Run("empty list", func(t *testing.T) { res1, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ - Repo: &argoappv1.Repository{}, - ApplicationSource: &argoappv1.ApplicationSource{Path: "./testdata/empty-list"}, - NoCache: true, + Repo: &argoappv1.Repository{}, + ApplicationSource: &argoappv1.ApplicationSource{Path: "./testdata/empty-list"}, + NoCache: true, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.Nil(t, err) assert.Equal(t, len(res1.Manifests), 1) @@ -1178,9 +1442,11 @@ func TestGenerateNullList(t *testing.T) { t.Run("weird list", func(t *testing.T) { res1, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ - Repo: &argoappv1.Repository{}, - ApplicationSource: &argoappv1.ApplicationSource{Path: "./testdata/weird-list"}, - NoCache: true, + Repo: &argoappv1.Repository{}, + ApplicationSource: &argoappv1.ApplicationSource{Path: "./testdata/weird-list"}, + NoCache: true, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.Nil(t, err) assert.Len(t, res1.Manifests, 2) @@ -1188,66 +1454,25 @@ func TestGenerateNullList(t *testing.T) { } func TestIdentifyAppSourceTypeByAppDirWithKustomizations(t *testing.T) { - sourceType, err := GetAppSourceType(context.Background(), &argoappv1.ApplicationSource{}, "./testdata/kustomization_yaml", "testapp", map[string]bool{}, []string{}) + sourceType, err := GetAppSourceType(context.Background(), &argoappv1.ApplicationSource{}, "./testdata/kustomization_yaml", "./testdata", "testapp", map[string]bool{}, []string{}, []string{}) assert.Nil(t, err) assert.Equal(t, argoappv1.ApplicationSourceTypeKustomize, sourceType) - sourceType, err = GetAppSourceType(context.Background(), &argoappv1.ApplicationSource{}, "./testdata/kustomization_yml", "testapp", map[string]bool{}, []string{}) + sourceType, err = GetAppSourceType(context.Background(), &argoappv1.ApplicationSource{}, "./testdata/kustomization_yml", "./testdata", "testapp", map[string]bool{}, []string{}, []string{}) assert.Nil(t, err) assert.Equal(t, argoappv1.ApplicationSourceTypeKustomize, sourceType) - sourceType, err = GetAppSourceType(context.Background(), &argoappv1.ApplicationSource{}, "./testdata/Kustomization", "testapp", map[string]bool{}, []string{}) + sourceType, err = GetAppSourceType(context.Background(), &argoappv1.ApplicationSource{}, "./testdata/Kustomization", "./testdata", "testapp", map[string]bool{}, []string{}, []string{}) assert.Nil(t, err) assert.Equal(t, argoappv1.ApplicationSourceTypeKustomize, sourceType) } -func TestRunCustomTool(t *testing.T) { - service := newService(".") - - res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ - AppName: "test-app", - Namespace: "test-namespace", - ApplicationSource: &argoappv1.ApplicationSource{ - Plugin: &argoappv1.ApplicationSourcePlugin{ - Name: "test", - Env: argoappv1.Env{ - { - Name: "TEST_REVISION", - Value: "prefix-$ARGOCD_APP_REVISION", - }, - }, - }, - }, - Plugins: []*argoappv1.ConfigManagementPlugin{{ - Name: "test", - Generate: argoappv1.Command{ - Command: []string{"sh", "-c"}, - Args: []string{`echo "{\"kind\": \"FakeObject\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"GIT_ASKPASS\": \"$GIT_ASKPASS\", \"GIT_USERNAME\": \"$GIT_USERNAME\", \"GIT_PASSWORD\": \"$GIT_PASSWORD\"}, \"labels\": {\"revision\": \"$ARGOCD_ENV_TEST_REVISION\"}}}"`}, - }, - }}, - Repo: &argoappv1.Repository{ - Username: "foo", Password: "bar", - }, - }) - - assert.NoError(t, err) - assert.Equal(t, 1, len(res.Manifests)) - - obj := &unstructured.Unstructured{} - assert.NoError(t, json.Unmarshal([]byte(res.Manifests[0]), obj)) - - assert.Equal(t, obj.GetName(), "test-app") - assert.Equal(t, obj.GetNamespace(), "test-namespace") - assert.Empty(t, obj.GetAnnotations()["GIT_USERNAME"]) - assert.Empty(t, obj.GetAnnotations()["GIT_PASSWORD"]) - // Git client is mocked, so the revision is always mock.Anything - assert.Equal(t, map[string]string{"revision": "prefix-mock.Anything"}, obj.GetLabels()) -} - func TestGenerateFromUTF16(t *testing.T) { q := apiclient.ManifestRequest{ - Repo: &argoappv1.Repository{}, - ApplicationSource: &argoappv1.ApplicationSource{}, + Repo: &argoappv1.Repository{}, + ApplicationSource: &argoappv1.ApplicationSource{}, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, } res1, err := GenerateManifests(context.Background(), "./testdata/utf-16", "/", "", &q, false, &git.NoopCredsStore{}, resource.MustParse("0"), nil) assert.Nil(t, err) @@ -1255,7 +1480,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) @@ -1276,12 +1501,14 @@ func TestListApps(t *testing.T) { "oci-dependencies": "Helm", "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{}, @@ -1296,8 +1523,26 @@ func TestGetAppDetailsHelm(t *testing.T) { 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{}, + 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 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{}, @@ -1315,7 +1560,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{}, @@ -1328,11 +1573,11 @@ func TestGetAppDetailsKustomize(t *testing.T) { assert.Equal(t, "Kustomize", res.Type) assert.NotNil(t, res.Kustomize) - assert.EqualValues(t, []string{"nginx:1.15.4", "k8s.gcr.io/nginx-slim:0.8"}, res.Kustomize.Images) + assert.EqualValues(t, []string{"nginx:1.15.4", "registry.k8s.io/nginx-slim:0.8"}, res.Kustomize.Images) } func TestGetHelmCharts(t *testing.T) { - service := newService("../..") + service := newService(t, "../..") res, err := service.GetHelmCharts(context.Background(), &apiclient.HelmChartsRequest{Repo: &argoappv1.Repository{}}) // fix flakiness @@ -1353,7 +1598,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{ @@ -1421,10 +1666,16 @@ 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{Repo: &argoappv1.Repository{}, ApplicationSource: &src, VerifySignature: true} + q := apiclient.ManifestRequest{ + Repo: &argoappv1.Repository{}, + ApplicationSource: &src, + VerifySignature: true, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, + } res, err := service.GenerateManifest(context.Background(), &q) assert.NoError(t, err) @@ -1432,10 +1683,11 @@ 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} + q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, ProjectName: "something", + ProjectSourceRepos: []string{"*"}} res, err := service.GenerateManifest(context.Background(), &q) assert.NoError(t, err) @@ -1443,10 +1695,11 @@ 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} + q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, VerifySignature: true, ProjectName: "something", + ProjectSourceRepos: []string{"*"}} res, err := service.GenerateManifest(context.Background(), &q) assert.NoError(t, err) @@ -1454,10 +1707,11 @@ 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} + q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, VerifySignature: true, ProjectName: "something", + ProjectSourceRepos: []string{"*"}} res, err := service.GenerateManifest(context.Background(), &q) assert.NoError(t, err) @@ -1470,6 +1724,7 @@ func Test_newEnv(t *testing.T) { &argoappv1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: "my-app-name"}, &argoappv1.EnvEntry{Name: "ARGOCD_APP_NAMESPACE", Value: "my-namespace"}, &argoappv1.EnvEntry{Name: "ARGOCD_APP_REVISION", Value: "my-revision"}, + &argoappv1.EnvEntry{Name: "ARGOCD_APP_REVISION_SHORT", Value: "my-revi"}, &argoappv1.EnvEntry{Name: "ARGOCD_APP_SOURCE_REPO_URL", Value: "https://github.com/my-org/my-repo"}, &argoappv1.EnvEntry{Name: "ARGOCD_APP_SOURCE_PATH", Value: "my-path"}, &argoappv1.EnvEntry{Name: "ARGOCD_APP_SOURCE_TARGET_REVISION", Value: "my-target-revision"}, @@ -1485,7 +1740,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) @@ -1499,7 +1754,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{}, @@ -1512,7 +1767,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{}, @@ -1526,7 +1781,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{}, @@ -1540,7 +1795,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{}, @@ -1554,7 +1809,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{}, @@ -1568,7 +1823,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{}, @@ -1610,12 +1865,14 @@ 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{ Path: path, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) require.NoError(t, err) resourceByKindName := make(map[string]*unstructured.Unstructured) @@ -1639,12 +1896,14 @@ 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{ Path: path, }, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) require.NoError(t, err) resourceByKindName := make(map[string]*unstructured.Unstructured) @@ -1667,14 +1926,16 @@ 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{}, ApplicationSource: &argoappv1.ApplicationSource{ Path: path, }, - AppName: "testapp", + AppName: "testapp", + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) require.NoError(t, err) resourceByKindName := make(map[string]*unstructured.Unstructured) @@ -1696,15 +1957,38 @@ 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{}, ApplicationSource: &argoappv1.ApplicationSource{ Path: path, }, - AppName: "testapp2", + AppName: "testapp2", + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) require.NoError(t, err) resourceByKindName := make(map[string]*unstructured.Unstructured) @@ -1727,23 +2011,25 @@ 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, } sourceCopy := source.DeepCopy() // make a copy in case GenerateManifest mutates it. _, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ - Repo: &argoappv1.Repository{}, - ApplicationSource: sourceCopy, - AppName: "test", + Repo: &argoappv1.Repository{}, + ApplicationSource: sourceCopy, + AppName: "test", + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }) assert.NoError(t, err) res := &cache.CachedManifestResponse{} // Try to pull from the cache with a `source` that does not include any overrides. Overrides should not be // part of the cache key, because you can't get the overrides without a repo operation. And avoiding repo // operations is the point of the cache. - err = service.cache.GetManifests(mock.Anything, source, argoappv1.RefTargetRevisionMapping{}, &argoappv1.ClusterInfo{}, "", "", "", "test", res) + err = service.cache.GetManifests(mock.Anything, source, argoappv1.RefTargetRevisionMapping{}, &argoappv1.ClusterInfo{}, "", "", "", "test", res, nil) assert.NoError(t, err) }) }) @@ -1770,10 +2056,12 @@ func TestGenerateManifestWithAnnotatedAndRegularGitTagHashes(t *testing.T) { ApplicationSource: &argoappv1.ApplicationSource{ TargetRevision: regularGitTagHash, }, - NoCache: true, + NoCache: true, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }, wantError: false, - service: newServiceWithCommitSHA(".", regularGitTagHash), + service: newServiceWithCommitSHA(t, ".", regularGitTagHash), }, { @@ -1784,10 +2072,12 @@ func TestGenerateManifestWithAnnotatedAndRegularGitTagHashes(t *testing.T) { ApplicationSource: &argoappv1.ApplicationSource{ TargetRevision: annotatedGitTaghash, }, - NoCache: true, + NoCache: true, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }, wantError: false, - service: newServiceWithCommitSHA(".", annotatedGitTaghash), + service: newServiceWithCommitSHA(t, ".", annotatedGitTaghash), }, { @@ -1798,10 +2088,12 @@ func TestGenerateManifestWithAnnotatedAndRegularGitTagHashes(t *testing.T) { ApplicationSource: &argoappv1.ApplicationSource{ TargetRevision: invalidGitTaghash, }, - NoCache: true, + NoCache: true, + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, }, wantError: true, - service: newServiceWithCommitSHA(".", invalidGitTaghash), + service: newServiceWithCommitSHA(t, ".", invalidGitTaghash), }, } for _, tt := range tests { @@ -1823,6 +2115,44 @@ func TestGenerateManifestWithAnnotatedAndRegularGitTagHashes(t *testing.T) { } } +func TestGenerateManifestWithAnnotatedTagsAndMultiSourceApp(t *testing.T) { + annotatedGitTaghash := "95249be61b028d566c29d47b19e65c5603388a41" + + service := newServiceWithCommitSHA(t, ".", annotatedGitTaghash) + + refSources := map[string]*argoappv1.RefTarget{} + + refSources["$global"] = &argoappv1.RefTarget{ + TargetRevision: annotatedGitTaghash, + } + + refSources["$default"] = &argoappv1.RefTarget{ + TargetRevision: annotatedGitTaghash, + } + + manifestRequest := &apiclient.ManifestRequest{ + Repo: &argoappv1.Repository{}, + ApplicationSource: &argoappv1.ApplicationSource{ + TargetRevision: annotatedGitTaghash, + Helm: &argoappv1.ApplicationSourceHelm{ + ValueFiles: []string{"$global/values.yaml", "$default/secrets.yaml"}, + }, + }, + HasMultipleSources: true, + NoCache: true, + RefSources: refSources, + } + + response, err := service.GenerateManifest(context.Background(), manifestRequest) + if err != nil { + t.Errorf("unexpected %s", err) + } + + if response.Revision != annotatedGitTaghash { + t.Errorf("returned SHA %s is different from expected annotated tag %s", response.Revision, annotatedGitTaghash) + } +} + func TestFindResources(t *testing.T) { testCases := []struct { name string @@ -2373,7 +2703,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", @@ -2398,7 +2728,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{ @@ -2420,7 +2750,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{ @@ -2467,19 +2797,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) { @@ -2492,16 +2860,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 @@ -2551,16 +2919,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) }) } @@ -2578,7 +2957,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) { @@ -2602,19 +2981,51 @@ func Test_populateHelmAppDetails_values_symlinks(t *testing.T) { }) } -func TestOCIDependencies(t *testing.T) { +func TestGetHelmRepos_OCIDependencies(t *testing.T) { src := argoappv1.ApplicationSource{Path: "."} q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, HelmRepoCreds: []*argoappv1.RepoCreds{ {URL: "example.com", Username: "test", Password: "test", EnableOCI: true}, }} - err := populateRequestRepos("./testdata/oci-dependencies", &q) + helmRepos, err := getHelmRepos("./testdata/oci-dependencies", q.Repos, q.HelmRepoCreds) + assert.Nil(t, err) + + assert.Equal(t, len(helmRepos), 1) + assert.Equal(t, helmRepos[0].Username, "test") + assert.Equal(t, helmRepos[0].EnableOci, true) + assert.Equal(t, helmRepos[0].Repo, "example.com/myrepo") +} + +func TestGetHelmRepo_NamedRepos(t *testing.T) { + src := argoappv1.ApplicationSource{Path: "."} + q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, Repos: []*argoappv1.Repository{{ + Name: "custom-repo", + Repo: "https://example.com", + Username: "test", + }}} + + helmRepos, err := getHelmRepos("./testdata/helm-with-dependencies", q.Repos, q.HelmRepoCreds) + assert.Nil(t, err) + + assert.Equal(t, len(helmRepos), 1) + assert.Equal(t, helmRepos[0].Username, "test") + 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(q.Repos), 1) - assert.Equal(t, q.Repos[0].Username, "test") - assert.Equal(t, q.Repos[0].EnableOCI, true) - assert.Equal(t, q.Repos[0].Repo, "example.com") + 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) { @@ -2772,3 +3183,374 @@ func Test_getResolvedValueFiles(t *testing.T) { }) } } +func TestErrorGetGitDirectories(t *testing.T) { + type fields struct { + service *Service + } + type args struct { + ctx context.Context + request *apiclient.GitDirectoriesRequest + } + tests := []struct { + name string + fields fields + args args + want *apiclient.GitDirectoriesResponse + wantErr assert.ErrorAssertionFunc + }{ + {name: "InvalidRepo", fields: fields{service: newService(t, ".")}, args: args{ + ctx: context.TODO(), + request: &apiclient.GitDirectoriesRequest{ + Repo: nil, + SubmoduleEnabled: false, + Revision: "HEAD", + }, + }, want: nil, wantErr: assert.Error}, + {name: "InvalidResolveRevision", fields: fields{service: func() *Service { + 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) + paths.On("GetPathIfExists", mock.Anything).Return(".", nil) + }, ".") + return s + }()}, args: args{ + ctx: context.TODO(), + request: &apiclient.GitDirectoriesRequest{ + Repo: &argoappv1.Repository{Repo: "not-a-valid-url"}, + SubmoduleEnabled: false, + Revision: "sadfsadf", + }, + }, want: nil, wantErr: assert.Error}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tt.fields.service + got, err := s.GetGitDirectories(tt.args.ctx, tt.args.request) + if !tt.wantErr(t, err, fmt.Sprintf("GetGitDirectories(%v, %v)", tt.args.ctx, tt.args.request)) { + return + } + assert.Equalf(t, tt.want, got, "GetGitDirectories(%v, %v)", tt.args.ctx, tt.args.request) + }) + } +} + +func TestGetGitDirectories(t *testing.T) { + // test not using the cache + root := "./testdata/git-files-dirs" + 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) + gitClient.On("LsRemote", "HEAD").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil) + gitClient.On("Root").Return(root) + paths.On("GetPath", mock.Anything).Return(root, nil) + paths.On("GetPathIfExists", mock.Anything).Return(root, nil) + }, root) + dirRequest := &apiclient.GitDirectoriesRequest{ + Repo: &argoappv1.Repository{Repo: "a-url.com"}, + SubmoduleEnabled: false, + Revision: "HEAD", + } + directories, err := s.GetGitDirectories(context.TODO(), dirRequest) + assert.Nil(t, err) + assert.ElementsMatch(t, directories.GetPaths(), []string{"app", "app/bar", "app/foo/bar", "somedir", "app/foo"}) + + // do the same request again to use the cache + // we only allow CheckOut to be called once in the mock + 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) { + type fields struct { + service *Service + } + type args struct { + ctx context.Context + request *apiclient.GitFilesRequest + } + tests := []struct { + name string + fields fields + args args + want *apiclient.GitFilesResponse + wantErr assert.ErrorAssertionFunc + }{ + {name: "InvalidRepo", fields: fields{service: newService(t, ".")}, args: args{ + ctx: context.TODO(), + request: &apiclient.GitFilesRequest{ + Repo: nil, + SubmoduleEnabled: false, + Revision: "HEAD", + }, + }, want: nil, wantErr: assert.Error}, + {name: "InvalidResolveRevision", fields: fields{service: func() *Service { + 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) + paths.On("GetPathIfExists", mock.Anything).Return(".", nil) + }, ".") + return s + }()}, args: args{ + ctx: context.TODO(), + request: &apiclient.GitFilesRequest{ + Repo: &argoappv1.Repository{Repo: "not-a-valid-url"}, + SubmoduleEnabled: false, + Revision: "sadfsadf", + }, + }, want: nil, wantErr: assert.Error}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := tt.fields.service + got, err := s.GetGitFiles(tt.args.ctx, tt.args.request) + if !tt.wantErr(t, err, fmt.Sprintf("GetGitFiles(%v, %v)", tt.args.ctx, tt.args.request)) { + return + } + assert.Equalf(t, tt.want, got, "GetGitFiles(%v, %v)", tt.args.ctx, tt.args.request) + }) + } +} + +func TestGetGitFiles(t *testing.T) { + // test not using the cache + 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, _, 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) + gitClient.On("LsRemote", "HEAD").Return("632039659e542ed7de0c170a4fcc1c571b288fc0", nil) + gitClient.On("Root").Return(root) + gitClient.On("LsFiles", mock.Anything, mock.Anything).Once().Return(files, nil) + paths.On("GetPath", mock.Anything).Return(root, nil) + paths.On("GetPathIfExists", mock.Anything).Return(root, nil) + }, root) + filesRequest := &apiclient.GitFilesRequest{ + Repo: &argoappv1.Repository{Repo: "a-url.com"}, + SubmoduleEnabled: false, + Revision: "HEAD", + } + + // expected map + expected := make(map[string][]byte) + for _, filePath := range files { + fileContents, err := os.ReadFile(filePath) + assert.Nil(t, err) + expected[filePath] = fileContents + } + + fileResponse, err := s.GetGitFiles(context.TODO(), filesRequest) + assert.Nil(t, err) + assert.Equal(t, fileResponse.GetMap(), expected) + + // do the same request again to use the cache + // we only allow LsFiles to be called once in the mock + 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) { + r := getRepoSanitizerRegex("/tmp/_argocd-repo") + msg := r.ReplaceAllString("error message containing /tmp/_argocd-repo/SENSITIVE and other stuff", "") + assert.Equal(t, "error message containing and other stuff", msg) + 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 TestGetRefs_CacheWithLockDisabled(t *testing.T) { + // Test that when the lock is disabled the default behavior still works correctly + // Also shows the current issue with the git requests due to cache misses + dir := t.TempDir() + initGitRepo(t, newGitRepoOptions{ + path: dir, + createPath: false, + remote: "", + addEmptyCommit: true, + }) + // Test in-memory and redis + cacheMocks := newCacheMocksWithOpts(1*time.Minute, 1*time.Minute, 0) + t.Cleanup(cacheMocks.mockCache.StopRedisCallback) + var wg sync.WaitGroup + numberOfCallers := 10 + for i := 0; i < numberOfCallers; i++ { + wg.Add(1) + go func() { + defer wg.Done() + client, err := git.NewClient(fmt.Sprintf("file://%s", dir), git.NopCreds{}, true, false, "", git.WithCache(cacheMocks.cache, true)) + require.NoError(t, err) + refs, err := client.LsRefs() + assert.NoError(t, err) + assert.NotNil(t, refs) + assert.NotEqual(t, 0, len(refs.Branches), "Expected branches to be populated") + assert.NotEmpty(t, refs.Branches[0]) + }() + } + wg.Wait() + // Unlock should not have been called + cacheMocks.mockCache.AssertNumberOfCalls(t, "UnlockGitReferences", 0) + // Lock should not have been called + cacheMocks.mockCache.AssertNumberOfCalls(t, "TryLockGitRefCache", 0) +} + +func TestGetRefs_CacheDisabled(t *testing.T) { + // Test that default get refs with cache disabled does not call GetOrLockGitReferences + dir := t.TempDir() + initGitRepo(t, newGitRepoOptions{ + path: dir, + createPath: false, + remote: "", + addEmptyCommit: true, + }) + cacheMocks := newCacheMocks() + t.Cleanup(cacheMocks.mockCache.StopRedisCallback) + client, err := git.NewClient(fmt.Sprintf("file://%s", dir), git.NopCreds{}, true, false, "", git.WithCache(cacheMocks.cache, false)) + require.NoError(t, err) + refs, err := client.LsRefs() + assert.NoError(t, err) + assert.NotNil(t, refs) + assert.NotEqual(t, 0, len(refs.Branches), "Expected branches to be populated") + assert.NotEmpty(t, refs.Branches[0]) + // Unlock should not have been called + cacheMocks.mockCache.AssertNumberOfCalls(t, "UnlockGitReferences", 0) + cacheMocks.mockCache.AssertNumberOfCalls(t, "GetOrLockGitReferences", 0) +} + +func TestGetRefs_CacheWithLock(t *testing.T) { + // Test that there is only one call to SetGitReferences for the same repo which is done after the ls-remote + dir := t.TempDir() + initGitRepo(t, newGitRepoOptions{ + path: dir, + createPath: false, + remote: "", + addEmptyCommit: true, + }) + cacheMocks := newCacheMocks() + t.Cleanup(cacheMocks.mockCache.StopRedisCallback) + var wg sync.WaitGroup + numberOfCallers := 10 + for i := 0; i < numberOfCallers; i++ { + wg.Add(1) + go func() { + defer wg.Done() + client, err := git.NewClient(fmt.Sprintf("file://%s", dir), git.NopCreds{}, true, false, "", git.WithCache(cacheMocks.cache, true)) + require.NoError(t, err) + refs, err := client.LsRefs() + assert.NoError(t, err) + assert.NotNil(t, refs) + assert.NotEqual(t, 0, len(refs.Branches), "Expected branches to be populated") + assert.NotEmpty(t, refs.Branches[0]) + }() + } + wg.Wait() + // Unlock should not have been called + cacheMocks.mockCache.AssertNumberOfCalls(t, "UnlockGitReferences", 0) + cacheMocks.mockCache.AssertNumberOfCalls(t, "GetOrLockGitReferences", 0) +} + +func TestGetRefs_CacheUnlockedOnUpdateFailed(t *testing.T) { + // Worst case the ttl on the lock expires and the lock is removed + // however if the holder of the lock fails to update the cache the caller should remove the lock + // to allow other callers to attempt to update the cache as quickly as possible + dir := t.TempDir() + initGitRepo(t, newGitRepoOptions{ + path: dir, + createPath: false, + remote: "", + addEmptyCommit: true, + }) + cacheMocks := newCacheMocks() + t.Cleanup(cacheMocks.mockCache.StopRedisCallback) + repoUrl := fmt.Sprintf("file://%s", dir) + client, err := git.NewClient(repoUrl, git.NopCreds{}, true, false, "", git.WithCache(cacheMocks.cache, true)) + require.NoError(t, err) + refs, err := client.LsRefs() + assert.NoError(t, err) + assert.NotNil(t, refs) + assert.NotEqual(t, 0, len(refs.Branches), "Expected branches to be populated") + assert.NotEmpty(t, refs.Branches[0]) + var output [][2]string + err = cacheMocks.cacheutilCache.GetItem(fmt.Sprintf("git-refs|%s|%s", repoUrl, common.CacheVersion), &output) + assert.Error(t, err, "Should be a cache miss") + assert.Equal(t, 0, len(output), "Expected cache to be empty for key") + cacheMocks.mockCache.AssertNumberOfCalls(t, "UnlockGitReferences", 0) + cacheMocks.mockCache.AssertNumberOfCalls(t, "GetOrLockGitReferences", 0) +} + +func TestGetRefs_CacheLockTryLockGitRefCacheError(t *testing.T) { + // Worst case the ttl on the lock expires and the lock is removed + // however if the holder of the lock fails to update the cache the caller should remove the lock + // to allow other callers to attempt to update the cache as quickly as possible + dir := t.TempDir() + initGitRepo(t, newGitRepoOptions{ + path: dir, + createPath: false, + remote: "", + addEmptyCommit: true, + }) + cacheMocks := newCacheMocks() + t.Cleanup(cacheMocks.mockCache.StopRedisCallback) + repoUrl := fmt.Sprintf("file://%s", dir) + // buf := bytes.Buffer{} + // log.SetOutput(&buf) + client, err := git.NewClient(repoUrl, git.NopCreds{}, true, false, "", git.WithCache(cacheMocks.cache, true)) + require.NoError(t, err) + refs, err := client.LsRefs() + assert.NoError(t, err) + assert.NotNil(t, refs) +} + +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/git-files-dirs/app/bar/.hidden/.keep b/reposerver/repository/testdata/git-files-dirs/app/bar/.hidden/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/reposerver/repository/testdata/git-files-dirs/app/bar/.keep b/reposerver/repository/testdata/git-files-dirs/app/bar/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/reposerver/repository/testdata/git-files-dirs/app/foo/bar/config.yaml b/reposerver/repository/testdata/git-files-dirs/app/foo/bar/config.yaml new file mode 100644 index 0000000000000..433c6b94dc0cf --- /dev/null +++ b/reposerver/repository/testdata/git-files-dirs/app/foo/bar/config.yaml @@ -0,0 +1,2 @@ +version: 4.2.1a +name: fooaaaa \ No newline at end of file diff --git a/reposerver/repository/testdata/git-files-dirs/app/foo/config.yaml b/reposerver/repository/testdata/git-files-dirs/app/foo/config.yaml new file mode 100644 index 0000000000000..096b2f1a35b87 --- /dev/null +++ b/reposerver/repository/testdata/git-files-dirs/app/foo/config.yaml @@ -0,0 +1,2 @@ +version: 4.2.1 +name: foo \ No newline at end of file diff --git a/reposerver/repository/testdata/git-files-dirs/config.yaml b/reposerver/repository/testdata/git-files-dirs/config.yaml new file mode 100644 index 0000000000000..5c0feb3c03c8a --- /dev/null +++ b/reposerver/repository/testdata/git-files-dirs/config.yaml @@ -0,0 +1,2 @@ +version: 4.2.1.5 +name: foooooo \ No newline at end of file diff --git a/reposerver/repository/testdata/git-files-dirs/somedir/config.yaml b/reposerver/repository/testdata/git-files-dirs/somedir/config.yaml new file mode 100644 index 0000000000000..c66361bb14a46 --- /dev/null +++ b/reposerver/repository/testdata/git-files-dirs/somedir/config.yaml @@ -0,0 +1,2 @@ +version: 2.1 +name: fo \ No newline at end of file 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/helm-with-dependencies/Chart.yaml b/reposerver/repository/testdata/helm-with-dependencies/Chart.yaml new file mode 100644 index 0000000000000..4b616a6eb8494 --- /dev/null +++ b/reposerver/repository/testdata/helm-with-dependencies/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v2 +name: helm-with-dependencies +version: v1.0.0 +dependencies: + - name: helm + repository: "@custom-repo" + version: v1.0.0 diff --git a/reposerver/repository/testdata/invalid-metadata/bad.yaml b/reposerver/repository/testdata/invalid-metadata/bad.yaml new file mode 100644 index 0000000000000..83f48a40dc334 --- /dev/null +++ b/reposerver/repository/testdata/invalid-metadata/bad.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: my-map-annotation + annotations: + invalid: true +stringData: + foo: bar +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: my-map-label + labels: + invalid: true +stringData: + foo: bar diff --git a/reposerver/repository/testdata/nil-metadata-accessors/nil-metadata-accessors.yaml b/reposerver/repository/testdata/nil-metadata-accessors/nil-metadata-accessors.yaml new file mode 100644 index 0000000000000..53979de769c01 --- /dev/null +++ b/reposerver/repository/testdata/nil-metadata-accessors/nil-metadata-accessors.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: my-map + annotations: + labels: +stringData: + foo: bar diff --git a/reposerver/repository/testdata/oci-dependencies/Chart.yaml b/reposerver/repository/testdata/oci-dependencies/Chart.yaml index 3b39781ed6257..1674ae17c5516 100644 --- a/reposerver/repository/testdata/oci-dependencies/Chart.yaml +++ b/reposerver/repository/testdata/oci-dependencies/Chart.yaml @@ -2,5 +2,5 @@ name: my-chart version: 1.1.0 dependencies: - name: my-dependency - repository: oci://example.com + repository: oci://example.com/myrepo version: '*' \ No newline at end of file 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/repository/types.go b/reposerver/repository/types.go new file mode 100644 index 0000000000000..3e45a5bf3a1cf --- /dev/null +++ b/reposerver/repository/types.go @@ -0,0 +1,14 @@ +package repository + +// Chart see: https://helm.sh/docs/topics/charts/ for more details +type Chart struct { + Description string `yaml:"description,omitempty"` + Home string `yaml:"home,omitempty"` + Maintainers []Maintainer `yaml:"maintainers,omitempty"` +} + +type Maintainer struct { + Name string `yaml:"name,omitempty"` + Email string `yaml:"email,omitempty"` + Url string `yaml:"url,omitempty"` +} 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/apps.openshift.io/DeploymentConfig/health.lua b/resource_customizations/apps.openshift.io/DeploymentConfig/health.lua index 3be1879532158..0e3faafe4730b 100644 --- a/resource_customizations/apps.openshift.io/DeploymentConfig/health.lua +++ b/resource_customizations/apps.openshift.io/DeploymentConfig/health.lua @@ -1,7 +1,7 @@ -health_check = {} +local health_check = {} if obj.status ~= nil then if obj.status.conditions ~= nil and obj.status.replicas ~= nil then - numTrue = 0 + local numTrue = 0 for i, condition in pairs(obj.status.conditions) do if (condition.type == "Available" or (condition.type == "Progressing" and condition.reason == "NewReplicationControllerAvailable")) and condition.status == "True" then numTrue = numTrue + 1 diff --git a/resource_customizations/apps/DaemonSet/actions/discovery.lua b/resource_customizations/apps/DaemonSet/actions/discovery.lua index 49557377a831b..dc7f10431bc70 100644 --- a/resource_customizations/apps/DaemonSet/actions/discovery.lua +++ b/resource_customizations/apps/DaemonSet/actions/discovery.lua @@ -1,3 +1,3 @@ -actions = {} +local actions = {} actions["restart"] = {} return actions diff --git a/resource_customizations/apps/DaemonSet/actions/testdata/daemonset-restarted.yaml b/resource_customizations/apps/DaemonSet/actions/testdata/daemonset-restarted.yaml index dc06ffda1cd21..e6ff0363952ef 100644 --- a/resource_customizations/apps/DaemonSet/actions/testdata/daemonset-restarted.yaml +++ b/resource_customizations/apps/DaemonSet/actions/testdata/daemonset-restarted.yaml @@ -25,7 +25,7 @@ spec: name: daemonset spec: containers: - - image: k8s.gcr.io/nginx-slim:0.8 + - image: registry.k8s.io/nginx-slim:0.8 imagePullPolicy: IfNotPresent name: nginx resources: {} diff --git a/resource_customizations/apps/DaemonSet/actions/testdata/daemonset.yaml b/resource_customizations/apps/DaemonSet/actions/testdata/daemonset.yaml index 4d58cbd7cfdf5..d293188455b87 100644 --- a/resource_customizations/apps/DaemonSet/actions/testdata/daemonset.yaml +++ b/resource_customizations/apps/DaemonSet/actions/testdata/daemonset.yaml @@ -23,7 +23,7 @@ spec: name: daemonset spec: containers: - - image: k8s.gcr.io/nginx-slim:0.8 + - image: registry.k8s.io/nginx-slim:0.8 imagePullPolicy: IfNotPresent name: nginx resources: {} diff --git a/resource_customizations/apps/Deployment/actions/discovery.lua b/resource_customizations/apps/Deployment/actions/discovery.lua index 52b52fba81a06..d090d587769c7 100644 --- a/resource_customizations/apps/Deployment/actions/discovery.lua +++ b/resource_customizations/apps/Deployment/actions/discovery.lua @@ -1,4 +1,4 @@ -actions = {} +local actions = {} actions["restart"] = {} local paused = false diff --git a/resource_customizations/apps/Deployment/actions/testdata/deployment-pause.yaml b/resource_customizations/apps/Deployment/actions/testdata/deployment-pause.yaml index 38cb1faf8498f..3ddbbe3e5cef2 100644 --- a/resource_customizations/apps/Deployment/actions/testdata/deployment-pause.yaml +++ b/resource_customizations/apps/Deployment/actions/testdata/deployment-pause.yaml @@ -4,6 +4,8 @@ metadata: annotations: deployment.kubernetes.io/revision: "1" creationTimestamp: "2021-09-21T22:35:20Z" + name: nginx-deploy + namespace: default generation: 2 spec: paused: true diff --git a/resource_customizations/apps/Deployment/actions/testdata/deployment-resume.yaml b/resource_customizations/apps/Deployment/actions/testdata/deployment-resume.yaml index ea8d3b14de51d..8ccb8dcab0802 100644 --- a/resource_customizations/apps/Deployment/actions/testdata/deployment-resume.yaml +++ b/resource_customizations/apps/Deployment/actions/testdata/deployment-resume.yaml @@ -5,6 +5,8 @@ metadata: deployment.kubernetes.io/revision: "1" creationTimestamp: "2021-09-21T22:35:20Z" generation: 3 + name: nginx-deploy + namespace: default spec: progressDeadlineSeconds: 600 replicas: 3 diff --git a/resource_customizations/apps/StatefulSet/actions/discovery.lua b/resource_customizations/apps/StatefulSet/actions/discovery.lua index 49557377a831b..dc7f10431bc70 100644 --- a/resource_customizations/apps/StatefulSet/actions/discovery.lua +++ b/resource_customizations/apps/StatefulSet/actions/discovery.lua @@ -1,3 +1,3 @@ -actions = {} +local actions = {} actions["restart"] = {} return actions diff --git a/resource_customizations/apps/StatefulSet/actions/testdata/statefulset-restarted.yaml b/resource_customizations/apps/StatefulSet/actions/testdata/statefulset-restarted.yaml index 5a3ba88edc6d5..44f902f4fa22b 100644 --- a/resource_customizations/apps/StatefulSet/actions/testdata/statefulset-restarted.yaml +++ b/resource_customizations/apps/StatefulSet/actions/testdata/statefulset-restarted.yaml @@ -26,7 +26,7 @@ spec: kubectl.kubernetes.io/restartedAt: "0001-01-01T00:00:00Z" spec: containers: - - image: k8s.gcr.io/nginx-slim:0.8 + - image: registry.k8s.io/nginx-slim:0.8 imagePullPolicy: IfNotPresent name: nginx resources: {} diff --git a/resource_customizations/apps/StatefulSet/actions/testdata/statefulset.yaml b/resource_customizations/apps/StatefulSet/actions/testdata/statefulset.yaml index 2dfd355e624fe..7804814a65e6c 100644 --- a/resource_customizations/apps/StatefulSet/actions/testdata/statefulset.yaml +++ b/resource_customizations/apps/StatefulSet/actions/testdata/statefulset.yaml @@ -24,7 +24,7 @@ spec: app: statefulset spec: containers: - - image: k8s.gcr.io/nginx-slim:0.8 + - image: registry.k8s.io/nginx-slim:0.8 imagePullPolicy: IfNotPresent name: nginx resources: {} diff --git a/resource_customizations/argoproj.io/AnalysisRun/actions/discovery.lua b/resource_customizations/argoproj.io/AnalysisRun/actions/discovery.lua index b98eaf0febd87..b5c2ef8ffaa73 100644 --- a/resource_customizations/argoproj.io/AnalysisRun/actions/discovery.lua +++ b/resource_customizations/argoproj.io/AnalysisRun/actions/discovery.lua @@ -1,4 +1,4 @@ -actions = {} +local actions = {} actions["terminate"] = {["disabled"] = (obj.spec.terminate or obj.status.phase == "Successful" or obj.status.phase == "Failed" or diff --git a/resource_customizations/argoproj.io/AnalysisRun/health.lua b/resource_customizations/argoproj.io/AnalysisRun/health.lua index ea2f53a98902d..9329b138e37af 100644 --- a/resource_customizations/argoproj.io/AnalysisRun/health.lua +++ b/resource_customizations/argoproj.io/AnalysisRun/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} function messageOrDefault(field, default) if field ~= nil then diff --git a/resource_customizations/argoproj.io/ApplicationSet/health.lua b/resource_customizations/argoproj.io/ApplicationSet/health.lua index 3292ebb67e51f..3a0cd19bc6202 100644 --- a/resource_customizations/argoproj.io/ApplicationSet/health.lua +++ b/resource_customizations/argoproj.io/ApplicationSet/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then diff --git a/resource_customizations/argoproj.io/CronWorkflow/actions/action_test.yaml b/resource_customizations/argoproj.io/CronWorkflow/actions/action_test.yaml new file mode 100644 index 0000000000000..7fce1c3b36cf6 --- /dev/null +++ b/resource_customizations/argoproj.io/CronWorkflow/actions/action_test.yaml @@ -0,0 +1,7 @@ +actionTests: +- action: create-workflow + inputPath: testdata/cronworkflow.yaml + expectedOutputPath: testdata/workflow.yaml +- action: create-workflow + inputPath: testdata/cronworkflow-without-label.yaml + expectedOutputPath: testdata/workflow-without-label.yaml diff --git a/resource_customizations/argoproj.io/CronWorkflow/actions/create-workflow/action.lua b/resource_customizations/argoproj.io/CronWorkflow/actions/create-workflow/action.lua new file mode 100644 index 0000000000000..c41da30887ebe --- /dev/null +++ b/resource_customizations/argoproj.io/CronWorkflow/actions/create-workflow/action.lua @@ -0,0 +1,82 @@ +local os = require("os") + +-- This action constructs a Workflow resource from a CronWorkflow resource, to enable creating a CronWorkflow instance +-- on demand. +-- It returns an array with a single member - a table with the operation to perform (create) and the Workflow resource. +-- It mimics the output of "argo submit --from=CronWorkflow/" command, declaratively. + +-- This code is written to mimic what the Argo Workflows API server does to create a Workflow from a CronWorkflow. +-- https://github.com/argoproj/argo-workflows/blob/873a58de7dd9dad76d5577b8c4294a58b52849b8/workflow/common/convert.go#L12 + +-- Deep-copying an object is a ChatGPT generated code. +-- Since empty tables are treated as empty arrays, the resulting k8s resource might be invalid (arrays instead of maps). +-- So empty tables are not cloned to the target object. +function deepCopy(object) + local lookup_table = {} + local function _copy(obj) + if type(obj) ~= "table" then + return obj + elseif lookup_table[obj] then + return lookup_table[obj] + elseif next(obj) == nil then + return nil + else + local new_table = {} + lookup_table[obj] = new_table + for key, value in pairs(obj) do + new_table[_copy(key)] = _copy(value) + end + return setmetatable(new_table, getmetatable(obj)) + end + end + return _copy(object) +end + +local workflow = {} +workflow.apiVersion = "argoproj.io/v1alpha1" +workflow.kind = "Workflow" + +workflow.metadata = {} +workflow.metadata.name = obj.metadata.name .. "-" ..os.date("!%Y%m%d%H%M") +workflow.metadata.namespace = obj.metadata.namespace +workflow.metadata.labels = {} +workflow.metadata.annotations = {} +if (obj.spec.workflowMetadata ~= nil) then + if (obj.spec.workflowMetadata.labels ~= nil) then + workflow.metadata.labels = deepCopy(obj.spec.workflowMetadata.labels) + end + if (obj.spec.workflowMetadata.annotations ~= nil) then + workflow.metadata.annotations = deepCopy(obj.spec.workflowMetadata.annotations) + end +end +workflow.metadata.labels["workflows.argoproj.io/cron-workflow"] = obj.metadata.name +if (obj.metadata.labels ~= nil and obj.metadata.labels["workflows.argoproj.io/controller-instanceid"] ~= nil) then + workflow.metadata.labels["workflows.argoproj.io/controller-instanceid"] = obj.metadata.labels["workflows.argoproj.io/controller-instanceid"] +end +workflow.metadata.annotations["workflows.argoproj.io/scheduled-time"] = os.date("!%Y-%m-%dT%d:%H:%MZ") + +workflow.finalizers = {} +-- add all finalizers from obj.spec.workflowMetadata.finalizers +if (obj.spec.workflowMetadata ~= nil and obj.spec.workflowMetadata.finalizers ~= nil) then + for i, finalizer in ipairs(obj.spec.workflowMetadata.finalizers) do + workflow.finalizers[i] = finalizer + end +end + +local ownerRef = {} +ownerRef.apiVersion = obj.apiVersion +ownerRef.kind = obj.kind +ownerRef.name = obj.metadata.name +ownerRef.uid = obj.metadata.uid +workflow.metadata.ownerReferences = {} +workflow.metadata.ownerReferences[1] = ownerRef + +workflow.spec = deepCopy(obj.spec.workflowSpec) + +local impactedResource = {} +impactedResource.operation = "create" +impactedResource.resource = workflow +local result = {} +result[1] = impactedResource + +return result diff --git a/resource_customizations/argoproj.io/CronWorkflow/actions/discovery.lua b/resource_customizations/argoproj.io/CronWorkflow/actions/discovery.lua new file mode 100644 index 0000000000000..9a76d96643218 --- /dev/null +++ b/resource_customizations/argoproj.io/CronWorkflow/actions/discovery.lua @@ -0,0 +1,6 @@ +local actions = {} +actions["create-workflow"] = { + ["iconClass"] = "fa fa-fw fa-play", + ["displayName"] = "Create Workflow" +} +return actions \ No newline at end of file diff --git a/resource_customizations/argoproj.io/CronWorkflow/actions/testdata/cronworkflow-without-label.yaml b/resource_customizations/argoproj.io/CronWorkflow/actions/testdata/cronworkflow-without-label.yaml new file mode 100644 index 0000000000000..a9f9e2ed8d5c0 --- /dev/null +++ b/resource_customizations/argoproj.io/CronWorkflow/actions/testdata/cronworkflow-without-label.yaml @@ -0,0 +1,31 @@ +apiVersion: argoproj.io/v1alpha1 +kind: CronWorkflow +metadata: + annotations: + cronworkflows.argoproj.io/last-used-schedule: CRON_TZ=America/Los_Angeles * * * * * + name: hello-world + namespace: default +spec: + concurrencyPolicy: Replace + failedJobsHistoryLimit: 4 + schedule: '* * * * *' + startingDeadlineSeconds: 0 + successfulJobsHistoryLimit: 4 + suspend: true + timezone: America/Los_Angeles + workflowSpec: + entrypoint: whalesay + templates: + - container: + args: + - "\U0001F553 hello world. Scheduled on: {{workflow.scheduledTime}}" + command: + - cowsay + image: 'docker/whalesay:latest' + name: whalesay + workflowMetadata: + labels: + example: test + annotations: + another-example: another-test + finalizers: [test-finalizer] diff --git a/resource_customizations/argoproj.io/CronWorkflow/actions/testdata/cronworkflow.yaml b/resource_customizations/argoproj.io/CronWorkflow/actions/testdata/cronworkflow.yaml new file mode 100644 index 0000000000000..2a2c7d1807db4 --- /dev/null +++ b/resource_customizations/argoproj.io/CronWorkflow/actions/testdata/cronworkflow.yaml @@ -0,0 +1,34 @@ +apiVersion: argoproj.io/v1alpha1 +kind: CronWorkflow +metadata: + annotations: + cronworkflows.argoproj.io/last-used-schedule: CRON_TZ=America/Los_Angeles * * * * * + labels: + workflows.argoproj.io/controller-instanceid: test-instance + app.kubernetes.io/instance: test + name: hello-world + namespace: default +spec: + concurrencyPolicy: Replace + failedJobsHistoryLimit: 4 + schedule: '* * * * *' + startingDeadlineSeconds: 0 + successfulJobsHistoryLimit: 4 + suspend: true + timezone: America/Los_Angeles + workflowSpec: + entrypoint: whalesay + templates: + - container: + args: + - "\U0001F553 hello world. Scheduled on: {{workflow.scheduledTime}}" + command: + - cowsay + image: 'docker/whalesay:latest' + name: whalesay + workflowMetadata: + labels: + example: test + annotations: + another-example: another-test + finalizers: [test-finalizer] diff --git a/resource_customizations/argoproj.io/CronWorkflow/actions/testdata/workflow-without-label.yaml b/resource_customizations/argoproj.io/CronWorkflow/actions/testdata/workflow-without-label.yaml new file mode 100644 index 0000000000000..1d20bc0d72a6a --- /dev/null +++ b/resource_customizations/argoproj.io/CronWorkflow/actions/testdata/workflow-without-label.yaml @@ -0,0 +1,26 @@ +- k8sOperation: create + unstructuredObj: + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + metadata: + annotations: + another-example: another-test + labels: + example: test + name: hello-world-202306221736 + namespace: default + ownerReferences: + - apiVersion: argoproj.io/v1alpha1 + kind: CronWorkflow + name: hello-world + finalizers: [test-finalizer] + spec: + entrypoint: whalesay + templates: + - container: + args: + - "\U0001F553 hello world. Scheduled on: {{workflow.scheduledTime}}" + command: + - cowsay + image: 'docker/whalesay:latest' + name: whalesay diff --git a/resource_customizations/argoproj.io/CronWorkflow/actions/testdata/workflow.yaml b/resource_customizations/argoproj.io/CronWorkflow/actions/testdata/workflow.yaml new file mode 100644 index 0000000000000..9f231dbb5c5b3 --- /dev/null +++ b/resource_customizations/argoproj.io/CronWorkflow/actions/testdata/workflow.yaml @@ -0,0 +1,28 @@ +- k8sOperation: create + unstructuredObj: + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + metadata: + annotations: + another-example: another-test + labels: + workflows.argoproj.io/cron-workflow: hello-world + workflows.argoproj.io/controller-instanceid: test-instance + example: test + name: hello-world-202306221736 + namespace: default + ownerReferences: + - apiVersion: argoproj.io/v1alpha1 + kind: CronWorkflow + name: hello-world + finalizers: [test-finalizer] + spec: + entrypoint: whalesay + templates: + - container: + args: + - "\U0001F553 hello world. Scheduled on: {{workflow.scheduledTime}}" + command: + - cowsay + image: 'docker/whalesay:latest' + name: whalesay diff --git a/resource_customizations/argoproj.io/CronWorkflow/health.lua b/resource_customizations/argoproj.io/CronWorkflow/health.lua index d1b736743504a..0a441df071a32 100644 --- a/resource_customizations/argoproj.io/CronWorkflow/health.lua +++ b/resource_customizations/argoproj.io/CronWorkflow/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then diff --git a/resource_customizations/argoproj.io/EventBus/health.lua b/resource_customizations/argoproj.io/EventBus/health.lua new file mode 100644 index 0000000000000..9e97eab7dfdf2 --- /dev/null +++ b/resource_customizations/argoproj.io/EventBus/health.lua @@ -0,0 +1,21 @@ +local hs={ status = "Progressing", message = "Waiting for initialization" } + +if obj.status ~= nil then + if obj.status.conditions ~= nil then + for _, condition in ipairs(obj.status.conditions) do + if condition.type == "Deployed" and condition.status == "False" then + hs.status = "Degraded" + hs.message = condition.message or condition.reason + return hs + end + if condition.type == "Deployed" and condition.status == "True" then + hs.status = "Healthy" + hs.message = condition.message or condition.reason + return hs + end + end + end +end + + +return hs diff --git a/resource_customizations/argoproj.io/EventBus/health_test.yaml b/resource_customizations/argoproj.io/EventBus/health_test.yaml new file mode 100644 index 0000000000000..7babe7fc7f9a3 --- /dev/null +++ b/resource_customizations/argoproj.io/EventBus/health_test.yaml @@ -0,0 +1,9 @@ +tests: + - healthStatus: + status: Healthy + message: "JetStream is deployed" + inputPath: testdata/healthy.yaml + - healthStatus: + status: Degraded + message: 'failed to get jetstream version, err: unsupported version "iwillfail", supported versions: "2.9.5,latest"' + inputPath: testdata/degraded.yaml \ No newline at end of file diff --git a/resource_customizations/argoproj.io/EventBus/testdata/degraded.yaml b/resource_customizations/argoproj.io/EventBus/testdata/degraded.yaml new file mode 100644 index 0000000000000..4ffd1cf6a9623 --- /dev/null +++ b/resource_customizations/argoproj.io/EventBus/testdata/degraded.yaml @@ -0,0 +1,21 @@ +apiVersion: argoproj.io/v1alpha1 +kind: EventBus +metadata: + name: test + namespace: eventbus-test +spec: + jetstream: + replicas: 3 + version: iwillfail +status: + conditions: + - lastTransitionTime: null + status: 'True' + type: Configured + - lastTransitionTime: null + message: >- + failed to get jetstream version, err: unsupported version "iwillfail", + supported versions: "2.9.5,latest" + reason: JetStreamStatefulSetFailed + status: 'False' + type: Deployed \ No newline at end of file diff --git a/resource_customizations/argoproj.io/EventBus/testdata/healthy.yaml b/resource_customizations/argoproj.io/EventBus/testdata/healthy.yaml new file mode 100644 index 0000000000000..8db1455a14d8e --- /dev/null +++ b/resource_customizations/argoproj.io/EventBus/testdata/healthy.yaml @@ -0,0 +1,19 @@ +apiVersion: argoproj.io/v1alpha1 +kind: EventBus +metadata: + name: test + namespace: eventbus-test +spec: + jetstream: + replicas: 3 + version: latest +status: + conditions: + - lastTransitionTime: '2022-12-30T11:44:15Z' + status: 'True' + type: Configured + - lastTransitionTime: '2022-12-30T11:44:15Z' + message: JetStream is deployed + reason: Succeeded + status: 'True' + type: Deployed \ No newline at end of file diff --git a/resource_customizations/argoproj.io/Experiment/health.lua b/resource_customizations/argoproj.io/Experiment/health.lua index 1587f684cdef1..ad11caf5ebea7 100644 --- a/resource_customizations/argoproj.io/Experiment/health.lua +++ b/resource_customizations/argoproj.io/Experiment/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.phase == "Pending" then hs.status = "Progressing" diff --git a/resource_customizations/argoproj.io/Rollout/actions/discovery.lua b/resource_customizations/argoproj.io/Rollout/actions/discovery.lua index 93d09d978ed12..86a5307e0023b 100644 --- a/resource_customizations/argoproj.io/Rollout/actions/discovery.lua +++ b/resource_customizations/argoproj.io/Rollout/actions/discovery.lua @@ -1,4 +1,4 @@ -actions = {} +local actions = {} actions["restart"] = {["disabled"] = false} local paused = false @@ -9,13 +9,13 @@ elseif obj.spec.paused ~= nil then end actions["resume"] = {["disabled"] = not(paused)} -fullyPromoted = obj.status.currentPodHash == obj.status.stableRS +local fullyPromoted = obj.status.currentPodHash == obj.status.stableRS actions["abort"] = {["disabled"] = fullyPromoted or obj.status.abort} actions["retry"] = {["disabled"] = fullyPromoted or not(obj.status.abort)} actions["promote-full"] = {["disabled"] = true} if obj.status ~= nil and not(fullyPromoted) then - generation = tonumber(obj.status.observedGeneration) + local generation = tonumber(obj.status.observedGeneration) if generation == nil or generation > obj.metadata.generation then -- rollouts v0.9 - full promotion only supported for canary actions["promote-full"] = {["disabled"] = obj.spec.strategy.blueGreen ~= nil} diff --git a/resource_customizations/argoproj.io/Rollout/actions/promote-full/action.lua b/resource_customizations/argoproj.io/Rollout/actions/promote-full/action.lua index 431c3f9279da0..90805995b1381 100644 --- a/resource_customizations/argoproj.io/Rollout/actions/promote-full/action.lua +++ b/resource_customizations/argoproj.io/Rollout/actions/promote-full/action.lua @@ -1,5 +1,5 @@ if obj.status ~= nil then - generation = tonumber(obj.status.observedGeneration) + local generation = tonumber(obj.status.observedGeneration) if generation == nil or generation > obj.metadata.generation then -- rollouts v0.9 and below obj.status.abort = nil diff --git a/resource_customizations/argoproj.io/Rollout/health.lua b/resource_customizations/argoproj.io/Rollout/health.lua index 8d352a3ad7f30..ec733a87c106c 100644 --- a/resource_customizations/argoproj.io/Rollout/health.lua +++ b/resource_customizations/argoproj.io/Rollout/health.lua @@ -1,9 +1,9 @@ function checkReplicasStatus(obj) - hs = {} - desiredReplicas = getNumberValueOrDefault(obj.spec.replicas, 1) + local hs = {} + local desiredReplicas = getNumberValueOrDefault(obj.spec.replicas, 1) statusReplicas = getNumberValueOrDefault(obj.status.replicas, 0) updatedReplicas = getNumberValueOrDefault(obj.status.updatedReplicas, 0) - availableReplicas = getNumberValueOrDefault(obj.status.availableReplicas, 0) + local availableReplicas = getNumberValueOrDefault(obj.status.availableReplicas, 0) if updatedReplicas < desiredReplicas then hs.status = "Progressing" @@ -38,7 +38,7 @@ function getNumberValueOrDefault(field, default) end function checkPaused(obj) - hs = {} + local hs = {} hs.status = "Suspended" hs.message = "Rollout is paused" if obj.status.pauseConditions ~= nil and table.getn(obj.status.pauseConditions) > 0 then @@ -73,12 +73,12 @@ function isWorkloadGenerationObserved(obj) -- rollout is v1.0 or earlier return true end - workloadGen = tonumber(obj.metadata.annotations["rollout.argoproj.io/workload-generation"]) - observedWorkloadGen = tonumber(obj.status.workloadObservedGeneration) + local workloadGen = tonumber(obj.metadata.annotations["rollout.argoproj.io/workload-generation"]) + local observedWorkloadGen = tonumber(obj.status.workloadObservedGeneration) return workloadGen == observedWorkloadGen end -hs = {} +local hs = {} if not isGenerationObserved(obj) or not isWorkloadGenerationObserved(obj) then hs.status = "Progressing" hs.message = "Waiting for rollout spec update to be observed" @@ -115,7 +115,7 @@ for _, condition in ipairs(obj.status.conditions) do end end -isPaused = checkPaused(obj) +local isPaused = checkPaused(obj) if isPaused ~= nil then return isPaused end @@ -132,7 +132,7 @@ if replicasHS ~= nil then end -stableRS = getStableRS(obj) +local stableRS = getStableRS(obj) if obj.spec.strategy.blueGreen ~= nil then if obj.status.blueGreen == nil or obj.status.blueGreen.activeSelector ~= obj.status.currentPodHash then diff --git a/resource_customizations/argoproj.io/WorkflowTemplate/actions/action_test.yaml b/resource_customizations/argoproj.io/WorkflowTemplate/actions/action_test.yaml new file mode 100644 index 0000000000000..db503fe0b6aae --- /dev/null +++ b/resource_customizations/argoproj.io/WorkflowTemplate/actions/action_test.yaml @@ -0,0 +1,4 @@ +actionTests: +- action: create-workflow + inputPath: testdata/workflowtemplate.yaml + expectedOutputPath: testdata/workflow.yaml diff --git a/resource_customizations/argoproj.io/WorkflowTemplate/actions/create-workflow/action.lua b/resource_customizations/argoproj.io/WorkflowTemplate/actions/create-workflow/action.lua new file mode 100644 index 0000000000000..1eaffc4771ad5 --- /dev/null +++ b/resource_customizations/argoproj.io/WorkflowTemplate/actions/create-workflow/action.lua @@ -0,0 +1,39 @@ +local os = require("os") + +-- This action constructs a Workflow resource from a WorkflowTemplate resource, to enable creating a WorkflowTemplate instance +-- on demand. +-- It returns an array with a single member - a table with the operation to perform (create) and the Workflow resource. +-- It mimics the output of "argo submit --from=workflowtemplate/" command, declaratively. + +-- This code is written to mimic what the Argo Workflows API server does to create a Workflow from a WorkflowTemplate. +-- https://github.com/argoproj/argo-workflows/blob/873a58de7dd9dad76d5577b8c4294a58b52849b8/workflow/common/convert.go#L34 + +local workflow = {} +workflow.apiVersion = "argoproj.io/v1alpha1" +workflow.kind = "Workflow" + +workflow.metadata = {} +workflow.metadata.name = obj.metadata.name .. "-" ..os.date("!%Y%m%d%H%M") +workflow.metadata.namespace = obj.metadata.namespace +workflow.metadata.labels = {} +workflow.metadata.labels["workflows.argoproj.io/workflow-template"] = obj.metadata.name + +workflow.spec = {} +workflow.spec.workflowTemplateRef = {} +workflow.spec.workflowTemplateRef.name = obj.metadata.name + +local ownerRef = {} +ownerRef.apiVersion = obj.apiVersion +ownerRef.kind = obj.kind +ownerRef.name = obj.metadata.name +ownerRef.uid = obj.metadata.uid +workflow.metadata.ownerReferences = {} +workflow.metadata.ownerReferences[1] = ownerRef + +local impactedResource = {} +impactedResource.operation = "create" +impactedResource.resource = workflow +local result = {} +result[1] = impactedResource + +return result diff --git a/resource_customizations/argoproj.io/WorkflowTemplate/actions/discovery.lua b/resource_customizations/argoproj.io/WorkflowTemplate/actions/discovery.lua new file mode 100644 index 0000000000000..9a76d96643218 --- /dev/null +++ b/resource_customizations/argoproj.io/WorkflowTemplate/actions/discovery.lua @@ -0,0 +1,6 @@ +local actions = {} +actions["create-workflow"] = { + ["iconClass"] = "fa fa-fw fa-play", + ["displayName"] = "Create Workflow" +} +return actions \ No newline at end of file diff --git a/resource_customizations/argoproj.io/WorkflowTemplate/actions/testdata/workflow.yaml b/resource_customizations/argoproj.io/WorkflowTemplate/actions/testdata/workflow.yaml new file mode 100644 index 0000000000000..46063bee03397 --- /dev/null +++ b/resource_customizations/argoproj.io/WorkflowTemplate/actions/testdata/workflow.yaml @@ -0,0 +1,16 @@ +- k8sOperation: create + unstructuredObj: + apiVersion: argoproj.io/v1alpha1 + kind: Workflow + metadata: + labels: + workflows.argoproj.io/workflow-template: workflow-template-submittable + name: workflow-template-submittable-202306221735 + namespace: default + ownerReferences: + - apiVersion: argoproj.io/v1alpha1 + kind: WorkflowTemplate + name: workflow-template-submittable + spec: + workflowTemplateRef: + name: workflow-template-submittable diff --git a/resource_customizations/argoproj.io/WorkflowTemplate/actions/testdata/workflowtemplate.yaml b/resource_customizations/argoproj.io/WorkflowTemplate/actions/testdata/workflowtemplate.yaml new file mode 100644 index 0000000000000..5b7d2319e9c9e --- /dev/null +++ b/resource_customizations/argoproj.io/WorkflowTemplate/actions/testdata/workflowtemplate.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: WorkflowTemplate +metadata: + labels: + app.kubernetes.io/instance: test + name: workflow-template-submittable + namespace: default +spec: + arguments: + parameters: + - name: message + value: hello world + entrypoint: whalesay-template + templates: + - container: + args: + - '{{inputs.parameters.message}}' + command: + - cowsay + image: docker/whalesay + inputs: + parameters: + - name: message + name: whalesay-template diff --git a/resource_customizations/batch/CronJob/actions/action_test.yaml b/resource_customizations/batch/CronJob/actions/action_test.yaml new file mode 100644 index 0000000000000..a9b5320db5721 --- /dev/null +++ b/resource_customizations/batch/CronJob/actions/action_test.yaml @@ -0,0 +1,4 @@ +actionTests: +- action: create-job + inputPath: testdata/cronjob.yaml + expectedOutputPath: testdata/job.yaml diff --git a/resource_customizations/batch/CronJob/actions/create-job/action.lua b/resource_customizations/batch/CronJob/actions/create-job/action.lua new file mode 100644 index 0000000000000..a6f3253a5b757 --- /dev/null +++ b/resource_customizations/batch/CronJob/actions/create-job/action.lua @@ -0,0 +1,64 @@ +local os = require("os") + +-- This action constructs a Job resource from a CronJob resource, to enable creating a CronJob instance on demand. +-- It returns an array with a single member - a table with the operation to perform (create) and the Job resource. +-- It mimics the output of "kubectl create job --from=" command, declaratively. + +-- Deep-copying an object is a ChatGPT generated code. +-- Since empty tables are treated as empty arrays, the resulting k8s resource might be invalid (arrays instead of maps). +-- So empty tables are not cloned to the target object. +function deepCopy(object) + local lookup_table = {} + local function _copy(obj) + if type(obj) ~= "table" then + return obj + elseif lookup_table[obj] then + return lookup_table[obj] + elseif next(obj) == nil then + return nil + else + local new_table = {} + lookup_table[obj] = new_table + for key, value in pairs(obj) do + new_table[_copy(key)] = _copy(value) + end + return setmetatable(new_table, getmetatable(obj)) + end + end + return _copy(object) +end + +local job = {} +job.apiVersion = "batch/v1" +job.kind = "Job" + +job.metadata = deepCopy(obj.spec.jobTemplate.metadata) +if job.metadata == nil then + job.metadata = {} +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 + +job.spec = deepCopy(obj.spec.jobTemplate.spec) + +local impactedResource = {} +impactedResource.operation = "create" +impactedResource.resource = job +local result = {} +result[1] = impactedResource + +return result diff --git a/resource_customizations/batch/CronJob/actions/discovery.lua b/resource_customizations/batch/CronJob/actions/discovery.lua new file mode 100644 index 0000000000000..61be2c3500122 --- /dev/null +++ b/resource_customizations/batch/CronJob/actions/discovery.lua @@ -0,0 +1,6 @@ +local actions = {} +actions["create-job"] = { + ["iconClass"] = "fa fa-fw fa-play", + ["displayName"] = "Create Job" +} +return actions \ No newline at end of file diff --git a/resource_customizations/batch/CronJob/actions/testdata/cronjob.yaml b/resource_customizations/batch/CronJob/actions/testdata/cronjob.yaml new file mode 100644 index 0000000000000..2c45c5eae1f38 --- /dev/null +++ b/resource_customizations/batch/CronJob/actions/testdata/cronjob.yaml @@ -0,0 +1,33 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: hello + namespace: test-ns + uid: "123" +spec: + schedule: "* * * * *" + jobTemplate: + metadata: + labels: + my: label + annotations: + my: annotation + spec: + ttlSecondsAfterFinished: 100 + template: + metadata: + labels: + pod: label + annotations: + pod: annotation + spec: + containers: + - name: hello + image: busybox:1.28 + imagePullPolicy: IfNotPresent + command: + - /bin/sh + - -c + - date; echo Hello from the Kubernetes cluster + resources: {} + restartPolicy: OnFailure \ No newline at end of file diff --git a/resource_customizations/batch/CronJob/actions/testdata/job.yaml b/resource_customizations/batch/CronJob/actions/testdata/job.yaml new file mode 100644 index 0000000000000..322ab0480beb5 --- /dev/null +++ b/resource_customizations/batch/CronJob/actions/testdata/job.yaml @@ -0,0 +1,30 @@ +- k8sOperation: create + unstructuredObj: + apiVersion: batch/v1 + kind: Job + metadata: + name: hello-00000000000 + namespace: test-ns + labels: + my: label + annotations: + cronjob.kubernetes.io/instantiate: manual + my: annotation + spec: + ttlSecondsAfterFinished: 100 + template: + metadata: + labels: + pod: label + annotations: + pod: annotation + spec: + containers: + - name: hello + image: busybox:1.28 + imagePullPolicy: IfNotPresent + command: + - /bin/sh + - -c + - date; echo Hello from the Kubernetes cluster + 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/bitnami.com/SealedSecret/health.lua b/resource_customizations/bitnami.com/SealedSecret/health.lua index 2e3bc3a497223..e18a9a8a79bec 100644 --- a/resource_customizations/bitnami.com/SealedSecret/health.lua +++ b/resource_customizations/bitnami.com/SealedSecret/health.lua @@ -1,4 +1,4 @@ -health_status={} +local health_status={} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do diff --git a/resource_customizations/cassandra.rook.io/Cluster/health.lua b/resource_customizations/cassandra.rook.io/Cluster/health.lua index 5bf48f6c9c49f..74979f8612f3c 100644 --- a/resource_customizations/cassandra.rook.io/Cluster/health.lua +++ b/resource_customizations/cassandra.rook.io/Cluster/health.lua @@ -1,7 +1,7 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.racks ~= nil then - all_racks_good = true + local all_racks_good = true for key, value in pairs(obj.status.racks) do if all_racks_good and value.members ~= nil and value.readyMembers ~= nil and value.members ~= value.readyMembers then all_racks_good = false diff --git a/resource_customizations/cassandra.rook.io/Cluster/testdata/healthy.yaml b/resource_customizations/cassandra.rook.io/Cluster/testdata/healthy.yaml index fbfdce3ca4358..b42422a56f874 100644 --- a/resource_customizations/cassandra.rook.io/Cluster/testdata/healthy.yaml +++ b/resource_customizations/cassandra.rook.io/Cluster/testdata/healthy.yaml @@ -66,7 +66,7 @@ spec: memory: 32Gi limits: cpu: 8 - memory: 32Gi + memory: 32Gi # A key/value list of annotations annotations: # key: value @@ -75,11 +75,11 @@ spec: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - - key: failure-domain.beta.kubernetes.io/region + - key: topology.kubernetes.io/region operator: In values: - us-east-1 - - key: failure-domain.beta.kubernetes.io/zone + - key: topology.kubernetes.io/zone operator: In values: - us-east-1a @@ -93,4 +93,4 @@ status: readyMembers: 3 us-east-1c: members: 3 - readyMembers: 3 \ No newline at end of file + readyMembers: 3 diff --git a/resource_customizations/cassandra.rook.io/Cluster/testdata/progressing.yaml b/resource_customizations/cassandra.rook.io/Cluster/testdata/progressing.yaml index 98c1a65bfc482..4034beca0d621 100644 --- a/resource_customizations/cassandra.rook.io/Cluster/testdata/progressing.yaml +++ b/resource_customizations/cassandra.rook.io/Cluster/testdata/progressing.yaml @@ -75,11 +75,11 @@ spec: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - - key: failure-domain.beta.kubernetes.io/region + - key: topology.kubernetes.io/region operator: In values: - us-east-1 - - key: failure-domain.beta.kubernetes.io/zone + - key: topology.kubernetes.io/zone operator: In values: - us-east-1a diff --git a/resource_customizations/cdi.kubevirt.io/DataVolume/health.lua b/resource_customizations/cdi.kubevirt.io/DataVolume/health.lua index 73cdef241fa8c..10e3d1b9a91b7 100644 --- a/resource_customizations/cdi.kubevirt.io/DataVolume/health.lua +++ b/resource_customizations/cdi.kubevirt.io/DataVolume/health.lua @@ -1,4 +1,4 @@ -hs = { status="Progressing", message="No status available"} +local hs = { status="Progressing", message="No status available"} if obj.status ~= nil then if obj.status.phase ~= nil then hs.message = obj.status.phase diff --git a/resource_customizations/cert-manager.io/Certificate/health.lua b/resource_customizations/cert-manager.io/Certificate/health.lua index 209ebb596e149..fce5bcbe3d1d0 100644 --- a/resource_customizations/cert-manager.io/Certificate/health.lua +++ b/resource_customizations/cert-manager.io/Certificate/health.lua @@ -1,12 +1,17 @@ -hs = {} +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/health.lua b/resource_customizations/cert-manager.io/ClusterIssuer/health.lua new file mode 100644 index 0000000000000..b6eb208190496 --- /dev/null +++ b/resource_customizations/cert-manager.io/ClusterIssuer/health.lua @@ -0,0 +1,21 @@ +local hs = {} +if obj.status ~= nil then + if obj.status.conditions ~= nil then + 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 + return hs + end + if condition.type == "Ready" and condition.status == "True" then + hs.status = "Healthy" + hs.message = condition.message + return hs + end + end + end +end + +hs.status = "Progressing" +hs.message = "Initializing ClusterIssuer" +return hs diff --git a/resource_customizations/cert-manager.io/ClusterIssuer/health_test.yaml b/resource_customizations/cert-manager.io/ClusterIssuer/health_test.yaml new file mode 100644 index 0000000000000..1eda5cfb3ca4a --- /dev/null +++ b/resource_customizations/cert-manager.io/ClusterIssuer/health_test.yaml @@ -0,0 +1,14 @@ +tests: +- healthStatus: + status: Progressing + message: Initializing ClusterIssuer + inputPath: testdata/progressing_noStatus.yaml +- healthStatus: + status: Healthy + message: The ACME account was registered with the ACME server + inputPath: testdata/healthy_registered.yaml +- healthStatus: + status: Degraded + message: "Failed to verify ACME account: acme: : 404 page not found\n" + inputPath: testdata/degraded_acmeFailed.yaml + diff --git a/resource_customizations/cert-manager.io/ClusterIssuer/testdata/degraded_acmeFailed.yaml b/resource_customizations/cert-manager.io/ClusterIssuer/testdata/degraded_acmeFailed.yaml new file mode 100644 index 0000000000000..c99c1f4f84ba4 --- /dev/null +++ b/resource_customizations/cert-manager.io/ClusterIssuer/testdata/degraded_acmeFailed.yaml @@ -0,0 +1,26 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + creationTimestamp: "2019-02-15T19:23:48Z" + generation: 1 + name: test-issuer + resourceVersion: "68352438" + uid: 37f408e3-3157-11e9-be3f-42010a800011 +spec: + acme: + email: myemail@example.com + http01: {} + privateKeySecretRef: + key: "" + name: letsencrypt + server: https://acme-v02.api.letsencrypt.org/directory124 +status: + acme: + uri: "" + conditions: + - lastTransitionTime: "2019-02-15T19:23:53Z" + message: | + Failed to verify ACME account: acme: : 404 page not found + reason: ErrRegisterACMEAccount + status: "False" + type: Ready diff --git a/resource_customizations/cert-manager.io/ClusterIssuer/testdata/healthy_registered.yaml b/resource_customizations/cert-manager.io/ClusterIssuer/testdata/healthy_registered.yaml new file mode 100644 index 0000000000000..e883b51e3a793 --- /dev/null +++ b/resource_customizations/cert-manager.io/ClusterIssuer/testdata/healthy_registered.yaml @@ -0,0 +1,25 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + creationTimestamp: "2018-11-06T23:14:18Z" + generation: 1 + name: test-issuer + resourceVersion: "48889060" + uid: b0045219-e219-11e8-9f93-42010a80021d +spec: + acme: + email: myemail@example.com + http01: {} + privateKeySecretRef: + key: "" + name: letsencrypt + server: https://acme-v02.api.letsencrypt.org/directory +status: + acme: + uri: https://acme-v02.api.letsencrypt.org/acme/acct/45250083 + conditions: + - lastTransitionTime: "2018-12-06T06:42:59Z" + message: The ACME account was registered with the ACME server + reason: ACMEAccountRegistered + status: "True" + type: Ready diff --git a/resource_customizations/cert-manager.io/ClusterIssuer/testdata/progressing_noStatus.yaml b/resource_customizations/cert-manager.io/ClusterIssuer/testdata/progressing_noStatus.yaml new file mode 100644 index 0000000000000..4571d229ffed7 --- /dev/null +++ b/resource_customizations/cert-manager.io/ClusterIssuer/testdata/progressing_noStatus.yaml @@ -0,0 +1,16 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + creationTimestamp: "2018-11-06T23:14:18Z" + generation: 1 + name: test-issuer + resourceVersion: "48889060" + uid: b0045219-e219-11e8-9f93-42010a80021d +spec: + acme: + email: myemail@example.com + http01: {} + privateKeySecretRef: + key: "" + name: letsencrypt + server: https://acme-v02.api.letsencrypt.org/directory diff --git a/resource_customizations/cert-manager.io/Issuer/health.lua b/resource_customizations/cert-manager.io/Issuer/health.lua index 2626e18a1f69d..497a6a7f12e6f 100644 --- a/resource_customizations/cert-manager.io/Issuer/health.lua +++ b/resource_customizations/cert-manager.io/Issuer/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do 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/Certificate/health.lua b/resource_customizations/certmanager.k8s.io/Certificate/health.lua index 61b28c84b86ee..d512d2d422b5a 100644 --- a/resource_customizations/certmanager.k8s.io/Certificate/health.lua +++ b/resource_customizations/certmanager.k8s.io/Certificate/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do diff --git a/resource_customizations/certmanager.k8s.io/Issuer/health.lua b/resource_customizations/certmanager.k8s.io/Issuer/health.lua index 2626e18a1f69d..497a6a7f12e6f 100644 --- a/resource_customizations/certmanager.k8s.io/Issuer/health.lua +++ b/resource_customizations/certmanager.k8s.io/Issuer/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do 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/cloudfunctions.cnrm.cloud.google.com/CloudFunctionsFunction/health.lua b/resource_customizations/cloudfunctions.cnrm.cloud.google.com/CloudFunctionsFunction/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/cloudfunctions.cnrm.cloud.google.com/CloudFunctionsFunction/health.lua +++ b/resource_customizations/cloudfunctions.cnrm.cloud.google.com/CloudFunctionsFunction/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/cloudscheduler.cnrm.cloud.google.com/CloudSchedulerJob/health.lua b/resource_customizations/cloudscheduler.cnrm.cloud.google.com/CloudSchedulerJob/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/cloudscheduler.cnrm.cloud.google.com/CloudSchedulerJob/health.lua +++ b/resource_customizations/cloudscheduler.cnrm.cloud.google.com/CloudSchedulerJob/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/cluster.x-k8s.io/Cluster/health.lua b/resource_customizations/cluster.x-k8s.io/Cluster/health.lua index 3d3f1c4e3892d..3f02513e460a8 100644 --- a/resource_customizations/cluster.x-k8s.io/Cluster/health.lua +++ b/resource_customizations/cluster.x-k8s.io/Cluster/health.lua @@ -27,7 +27,7 @@ function getReadyContitionStatus(obj, hs) return hs end -hs = {} +local hs = {} if obj.spec.paused ~= nil and obj.spec.paused then hs.status = "Suspended" hs.message = "Cluster is paused" diff --git a/resource_customizations/cluster.x-k8s.io/Machine/health.lua b/resource_customizations/cluster.x-k8s.io/Machine/health.lua index 2b52a4351e7e2..146b795d7496d 100644 --- a/resource_customizations/cluster.x-k8s.io/Machine/health.lua +++ b/resource_customizations/cluster.x-k8s.io/Machine/health.lua @@ -1,5 +1,5 @@ function getStatusBasedOnPhase(obj) - hs = {} + local hs = {} hs.status = "Progressing" hs.message = "Waiting for machines" if obj.status ~= nil and obj.status.phase ~= nil then @@ -26,7 +26,7 @@ function getReadyContitionMessage(obj) return "Condition is unknown" end -hs = getStatusBasedOnPhase(obj) +local hs = getStatusBasedOnPhase(obj) if hs.status ~= "Healthy" then hs.message = getReadyContitionMessage(obj) end diff --git a/resource_customizations/cluster.x-k8s.io/MachineDeployment/health.lua b/resource_customizations/cluster.x-k8s.io/MachineDeployment/health.lua index 0ac402c638843..14b0103d19ad6 100644 --- a/resource_customizations/cluster.x-k8s.io/MachineDeployment/health.lua +++ b/resource_customizations/cluster.x-k8s.io/MachineDeployment/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} hs.status = "Progressing" hs.message = "Waiting for machines" diff --git a/resource_customizations/cluster.x-k8s.io/MachineHealthCheck/health.lua b/resource_customizations/cluster.x-k8s.io/MachineHealthCheck/health.lua index 18840408ecae8..b8cff71bbe94b 100644 --- a/resource_customizations/cluster.x-k8s.io/MachineHealthCheck/health.lua +++ b/resource_customizations/cluster.x-k8s.io/MachineHealthCheck/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} hs.status = "Progressing" hs.message = "" diff --git a/resource_customizations/compute.cnrm.cloud.google.com/ComputeDisk/health.lua b/resource_customizations/compute.cnrm.cloud.google.com/ComputeDisk/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/compute.cnrm.cloud.google.com/ComputeDisk/health.lua +++ b/resource_customizations/compute.cnrm.cloud.google.com/ComputeDisk/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } 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/elasticsearch.k8s.elastic.co/Elasticsearch/health.lua b/resource_customizations/elasticsearch.k8s.elastic.co/Elasticsearch/health.lua index 3bac570b0c4d7..241413e68f4b5 100644 --- a/resource_customizations/elasticsearch.k8s.elastic.co/Elasticsearch/health.lua +++ b/resource_customizations/elasticsearch.k8s.elastic.co/Elasticsearch/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.availableNodes ~= nil then local sum = 0 @@ -17,7 +17,7 @@ if obj.status ~= nil then hs.message = "Elasticsearch Cluster status is Green" return hs elseif obj.status.health == "yellow" then - hs.status = "Degraded" + hs.status = "Progressing" hs.message = "Elasticsearch Cluster status is Yellow. Check the status of indices, replicas and shards" return hs elseif obj.status.health == "red" then diff --git a/resource_customizations/elasticsearch.k8s.elastic.co/Elasticsearch/health_test.yaml b/resource_customizations/elasticsearch.k8s.elastic.co/Elasticsearch/health_test.yaml index 0a0ef51d16f6c..015bc145d8ff8 100644 --- a/resource_customizations/elasticsearch.k8s.elastic.co/Elasticsearch/health_test.yaml +++ b/resource_customizations/elasticsearch.k8s.elastic.co/Elasticsearch/health_test.yaml @@ -4,7 +4,7 @@ tests: message: "Elasticsearch Cluster status is Green" inputPath: testdata/ready_green.yaml - healthStatus: - status: Degraded + status: Progressing message: "Elasticsearch Cluster status is Yellow. Check the status of indices, replicas and shards" inputPath: testdata/ready_yellow.yaml - healthStatus: diff --git a/resource_customizations/embed.go b/resource_customizations/embed.go index 251b12293efac..8a4d5316cd3df 100644 --- a/resource_customizations/embed.go +++ b/resource_customizations/embed.go @@ -5,5 +5,6 @@ import ( ) // Embedded contains embedded resource customization +// //go:embed * var Embedded embed.FS diff --git a/resource_customizations/external-secrets.io/ClusterExternalSecret/health.lua b/resource_customizations/external-secrets.io/ClusterExternalSecret/health.lua new file mode 100644 index 0000000000000..b89fbd5965e6c --- /dev/null +++ b/resource_customizations/external-secrets.io/ClusterExternalSecret/health.lua @@ -0,0 +1,25 @@ +local hs = {} +if obj.status ~= nil then + if obj.status.conditions ~= nil then + -- For ClusterExternalSecret, new statuses are appended to the end of the list + local lastStatus = obj.status.conditions[#obj.status.conditions] + if lastStatus.type == "Ready" and lastStatus.status == "True" then + hs.status = "Healthy" + hs.message = lastStatus.message + return hs + end + if lastStatus.type == "PartiallyReady" and lastStatus.status == "True" then + hs.status = "Degraded" + hs.message = lastStatus.message + return hs + end + if lastStatus.type == "NotReady" and lastStatus.status == "True" then + hs.status = "Degraded" + hs.message = lastStatus.message + return hs + end + end +end +hs.status = "Progressing" +hs.message = "Waiting for ClusterExternalSecret" +return hs diff --git a/resource_customizations/external-secrets.io/ClusterExternalSecret/health_test.yaml b/resource_customizations/external-secrets.io/ClusterExternalSecret/health_test.yaml new file mode 100644 index 0000000000000..52e4c7c13740f --- /dev/null +++ b/resource_customizations/external-secrets.io/ClusterExternalSecret/health_test.yaml @@ -0,0 +1,21 @@ +tests: + - healthStatus: + status: Progressing + message: Waiting for ClusterExternalSecret + inputPath: testdata/progressing.yaml + - healthStatus: + status: Degraded + message: 'one or more namespaces failed' + inputPath: testdata/notready.yaml + - healthStatus: + status: Degraded + message: 'one or more namespaces failed' + inputPath: testdata/partiallyready.yaml + - healthStatus: + status: Degraded + message: 'one or more namespaces failed' + inputPath: testdata/partiallyready-multiple-conditions.yaml + - healthStatus: + status: Healthy + message: '' + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/healthy.yaml b/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/healthy.yaml new file mode 100644 index 0000000000000..1a5f61b44a48f --- /dev/null +++ b/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/healthy.yaml @@ -0,0 +1,37 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ClusterExternalSecret +metadata: + name: ces +spec: + externalSecretName: hello-world-es + externalSecretSpec: + data: + - remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /foo + property: key + secretKey: mykey + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: secretmanager + target: + creationPolicy: Owner + deletionPolicy: Retain + name: mysecret + template: + data: + somekey: '{{ .somecreds }}' + engineVersion: v2 + type: Opaque + namespaceSelector: + matchLabels: + cool: label +status: + conditions: + - message: one or more namespaces failed + status: "True" + type: PartiallyReady + - status: "True" + type: Ready diff --git a/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/notready.yaml b/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/notready.yaml new file mode 100644 index 0000000000000..eeea3069bfb2d --- /dev/null +++ b/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/notready.yaml @@ -0,0 +1,38 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ClusterExternalSecret +metadata: + name: ces +spec: + externalSecretName: hello-world-es + externalSecretSpec: + data: + - remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /foo + property: key + secretKey: mykey + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: secretmanager + target: + creationPolicy: Owner + deletionPolicy: Retain + name: mysecret + template: + data: + somekey: '{{ .somecreds }}' + engineVersion: v2 + type: Opaque + namespaceSelector: + matchLabels: + cool: label +status: + conditions: + - message: one or more namespaces failed + status: "True" + type: NotReady + failedNamespaces: + - namespace: default + reason: external secret already exists in namespace diff --git a/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/partiallyready-multiple-conditions.yaml b/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/partiallyready-multiple-conditions.yaml new file mode 100644 index 0000000000000..52f6141871de0 --- /dev/null +++ b/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/partiallyready-multiple-conditions.yaml @@ -0,0 +1,43 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ClusterExternalSecret +metadata: + name: ces +spec: + externalSecretName: hello-world-es + externalSecretSpec: + data: + - remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /foo + property: key + secretKey: mykey + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: secretmanager + target: + creationPolicy: Owner + deletionPolicy: Retain + name: mysecret + template: + data: + somekey: '{{ .somecreds }}' + engineVersion: v2 + type: Opaque + namespaceSelector: + matchLabels: + cool: label +status: + conditions: + - message: one or more namespaces failed + status: "True" + type: NotReady + - message: one or more namespaces failed + status: "True" + type: PartiallyReady + failedNamespaces: + - namespace: default + reason: external secret already exists in namespace + provisionedNamespaces: + - other-namespace diff --git a/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/partiallyready.yaml b/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/partiallyready.yaml new file mode 100644 index 0000000000000..f6a291526fd7f --- /dev/null +++ b/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/partiallyready.yaml @@ -0,0 +1,40 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ClusterExternalSecret +metadata: + name: ces +spec: + externalSecretName: hello-world-es + externalSecretSpec: + data: + - remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /foo + property: key + secretKey: mykey + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: secretmanager + target: + creationPolicy: Owner + deletionPolicy: Retain + name: mysecret + template: + data: + somekey: '{{ .somecreds }}' + engineVersion: v2 + type: Opaque + namespaceSelector: + matchLabels: + cool: label +status: + conditions: + - message: one or more namespaces failed + status: "True" + type: PartiallyReady + failedNamespaces: + - namespace: default + reason: external secret already exists in namespace + provisionedNamespaces: + - other-namespace diff --git a/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/progressing.yaml b/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/progressing.yaml new file mode 100644 index 0000000000000..8e326e413cf8a --- /dev/null +++ b/resource_customizations/external-secrets.io/ClusterExternalSecret/testdata/progressing.yaml @@ -0,0 +1,30 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ClusterExternalSecret +metadata: + name: ces +spec: + externalSecretName: hello-world-es + externalSecretSpec: + data: + - remoteRef: + conversionStrategy: Default + decodingStrategy: None + key: /foo + property: key + secretKey: mykey + refreshInterval: 1h + secretStoreRef: + kind: ClusterSecretStore + name: secretmanager + target: + creationPolicy: Owner + deletionPolicy: Retain + name: mysecret + template: + data: + somekey: '{{ .somecreds }}' + engineVersion: v2 + type: Opaque + namespaceSelector: + matchLabels: + cool: label diff --git a/resource_customizations/external-secrets.io/ClusterSecretStore/health.lua b/resource_customizations/external-secrets.io/ClusterSecretStore/health.lua new file mode 100644 index 0000000000000..4c430f78383f4 --- /dev/null +++ b/resource_customizations/external-secrets.io/ClusterSecretStore/health.lua @@ -0,0 +1,20 @@ +local hs = {} +if obj.status ~= nil then + if obj.status.conditions ~= nil then + 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 + return hs + end + if condition.type == "Ready" and condition.status == "True" then + hs.status = "Healthy" + hs.message = condition.message + return hs + end + end + end +end +hs.status = "Progressing" +hs.message = "Waiting for ClusterSecretStore" +return hs diff --git a/resource_customizations/external-secrets.io/ClusterSecretStore/health_test.yaml b/resource_customizations/external-secrets.io/ClusterSecretStore/health_test.yaml new file mode 100644 index 0000000000000..6e692158e6e10 --- /dev/null +++ b/resource_customizations/external-secrets.io/ClusterSecretStore/health_test.yaml @@ -0,0 +1,9 @@ +tests: + - healthStatus: + status: Degraded + message: 'unable to validate store' + inputPath: testdata/degraded.yaml + - healthStatus: + status: Healthy + message: 'store validated' + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/external-secrets.io/ClusterSecretStore/testdata/degraded.yaml b/resource_customizations/external-secrets.io/ClusterSecretStore/testdata/degraded.yaml new file mode 100644 index 0000000000000..1f00cc4ea61e7 --- /dev/null +++ b/resource_customizations/external-secrets.io/ClusterSecretStore/testdata/degraded.yaml @@ -0,0 +1,16 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ClusterSecretStore +metadata: + name: secretmanager +spec: + provider: + aws: + region: us-east-1 + service: SecretsManager +status: + conditions: + - lastTransitionTime: "2023-03-21T22:58:01Z" + message: unable to validate store + reason: ValidationFailed + status: "False" + type: Ready diff --git a/resource_customizations/external-secrets.io/ClusterSecretStore/testdata/healthy.yaml b/resource_customizations/external-secrets.io/ClusterSecretStore/testdata/healthy.yaml new file mode 100644 index 0000000000000..8c99de1326179 --- /dev/null +++ b/resource_customizations/external-secrets.io/ClusterSecretStore/testdata/healthy.yaml @@ -0,0 +1,17 @@ +apiVersion: external-secrets.io/v1beta1 +kind: ClusterSecretStore +metadata: + name: secretmanager +spec: + provider: + aws: + region: us-east-1 + service: SecretsManager +status: + capabilities: ReadWrite + conditions: + - lastTransitionTime: "2023-03-22T04:51:03Z" + message: store validated + reason: Valid + status: "True" + type: Ready diff --git a/resource_customizations/external-secrets.io/ExternalSecret/actions/action_test.yaml b/resource_customizations/external-secrets.io/ExternalSecret/actions/action_test.yaml new file mode 100644 index 0000000000000..83f49fcff7439 --- /dev/null +++ b/resource_customizations/external-secrets.io/ExternalSecret/actions/action_test.yaml @@ -0,0 +1,4 @@ +actionTests: + - action: refresh + inputPath: testdata/external-secret.yaml + expectedOutputPath: testdata/external-secret-updated.yaml diff --git a/resource_customizations/external-secrets.io/ExternalSecret/actions/discovery.lua b/resource_customizations/external-secrets.io/ExternalSecret/actions/discovery.lua new file mode 100644 index 0000000000000..89d806c8deceb --- /dev/null +++ b/resource_customizations/external-secrets.io/ExternalSecret/actions/discovery.lua @@ -0,0 +1,3 @@ +local actions = {} +actions["refresh"] = {["disabled"] = false} +return actions diff --git a/resource_customizations/external-secrets.io/ExternalSecret/actions/refresh/action.lua b/resource_customizations/external-secrets.io/ExternalSecret/actions/refresh/action.lua new file mode 100644 index 0000000000000..fa29c485fa16a --- /dev/null +++ b/resource_customizations/external-secrets.io/ExternalSecret/actions/refresh/action.lua @@ -0,0 +1,6 @@ +local os = require("os") +if obj.metadata.annotations == nil then + obj.metadata.annotations = {} +end +obj.metadata.annotations["force-sync"] = os.date("!%Y-%m-%dT%XZ") +return obj diff --git a/resource_customizations/external-secrets.io/ExternalSecret/actions/testdata/external-secret-updated.yaml b/resource_customizations/external-secrets.io/ExternalSecret/actions/testdata/external-secret-updated.yaml new file mode 100644 index 0000000000000..4266e9a5d18fd --- /dev/null +++ b/resource_customizations/external-secrets.io/ExternalSecret/actions/testdata/external-secret-updated.yaml @@ -0,0 +1,56 @@ +apiVersion: external-secrets.io/v1alpha1 +kind: ExternalSecret +metadata: + annotations: + force-sync: '0001-01-01T00:00:00Z' + creationTimestamp: '2021-11-16T21:59:33Z' + generation: 1 + name: test-healthy + namespace: argocd + resourceVersion: '136487331' + selfLink: /apis/external-secrets.io/v1alpha1/namespaces/argocd/externalsecrets/test-healthy + uid: 1e754a7e-0781-4d57-932d-4651d5b19586 +spec: + data: + - remoteRef: + key: secret/sa/example + property: api.address + secretKey: url + - remoteRef: + key: secret/sa/example + property: ca.crt + secretKey: ca + - remoteRef: + key: secret/sa/example + property: token + secretKey: token + refreshInterval: 1m + secretStoreRef: + kind: SecretStore + name: example + target: + creationPolicy: Owner + template: + data: + config: | + { + "bearerToken": "{{ .token | base64decode | toString }}", + "tlsClientConfig": { + "insecure": false, + "caData": "{{ .ca | toString }}" + } + } + name: cluster-test + server: '{{ .url | toString }}' + metadata: + labels: + argocd.argoproj.io/secret-type: cluster +status: + conditions: + - lastTransitionTime: '2021-11-16T21:59:34Z' + message: Secret was synced + reason: SecretSynced + status: 'True' + type: Ready + refreshTime: '2021-11-29T18:32:24Z' + syncedResourceVersion: 1-519a61da0dc68b2575b4f8efada70e42 diff --git a/resource_customizations/external-secrets.io/ExternalSecret/actions/testdata/external-secret.yaml b/resource_customizations/external-secrets.io/ExternalSecret/actions/testdata/external-secret.yaml new file mode 100644 index 0000000000000..da17edbfe902d --- /dev/null +++ b/resource_customizations/external-secrets.io/ExternalSecret/actions/testdata/external-secret.yaml @@ -0,0 +1,54 @@ +apiVersion: external-secrets.io/v1alpha1 +kind: ExternalSecret +metadata: + creationTimestamp: '2021-11-16T21:59:33Z' + generation: 1 + name: test-healthy + namespace: argocd + resourceVersion: '136487331' + selfLink: /apis/external-secrets.io/v1alpha1/namespaces/argocd/externalsecrets/test-healthy + uid: 1e754a7e-0781-4d57-932d-4651d5b19586 +spec: + data: + - remoteRef: + key: secret/sa/example + property: api.address + secretKey: url + - remoteRef: + key: secret/sa/example + property: ca.crt + secretKey: ca + - remoteRef: + key: secret/sa/example + property: token + secretKey: token + refreshInterval: 1m + secretStoreRef: + kind: SecretStore + name: example + target: + creationPolicy: Owner + template: + data: + config: | + { + "bearerToken": "{{ .token | base64decode | toString }}", + "tlsClientConfig": { + "insecure": false, + "caData": "{{ .ca | toString }}" + } + } + name: cluster-test + server: '{{ .url | toString }}' + metadata: + labels: + argocd.argoproj.io/secret-type: cluster +status: + conditions: + - lastTransitionTime: '2021-11-16T21:59:34Z' + message: Secret was synced + reason: SecretSynced + status: 'True' + type: Ready + refreshTime: '2021-11-29T18:32:24Z' + syncedResourceVersion: 1-519a61da0dc68b2575b4f8efada70e42 diff --git a/resource_customizations/external-secrets.io/ExternalSecret/health.lua b/resource_customizations/external-secrets.io/ExternalSecret/health.lua index 889c924d2a3db..4def31d95d7ff 100644 --- a/resource_customizations/external-secrets.io/ExternalSecret/health.lua +++ b/resource_customizations/external-secrets.io/ExternalSecret/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do diff --git a/resource_customizations/external-secrets.io/PushSecret/actions/action_test.yaml b/resource_customizations/external-secrets.io/PushSecret/actions/action_test.yaml new file mode 100644 index 0000000000000..457e5892667a3 --- /dev/null +++ b/resource_customizations/external-secrets.io/PushSecret/actions/action_test.yaml @@ -0,0 +1,4 @@ +actionTests: + - action: push + inputPath: testdata/push-secret.yaml + expectedOutputPath: testdata/push-secret-updated.yaml diff --git a/resource_customizations/external-secrets.io/PushSecret/actions/discovery.lua b/resource_customizations/external-secrets.io/PushSecret/actions/discovery.lua new file mode 100644 index 0000000000000..6b095fbd98dbe --- /dev/null +++ b/resource_customizations/external-secrets.io/PushSecret/actions/discovery.lua @@ -0,0 +1,3 @@ +actions = {} +actions["push"] = {["disabled"] = false} +return actions diff --git a/resource_customizations/external-secrets.io/PushSecret/actions/push/action.lua b/resource_customizations/external-secrets.io/PushSecret/actions/push/action.lua new file mode 100644 index 0000000000000..fa29c485fa16a --- /dev/null +++ b/resource_customizations/external-secrets.io/PushSecret/actions/push/action.lua @@ -0,0 +1,6 @@ +local os = require("os") +if obj.metadata.annotations == nil then + obj.metadata.annotations = {} +end +obj.metadata.annotations["force-sync"] = os.date("!%Y-%m-%dT%XZ") +return obj diff --git a/resource_customizations/external-secrets.io/PushSecret/actions/testdata/push-secret-updated.yaml b/resource_customizations/external-secrets.io/PushSecret/actions/testdata/push-secret-updated.yaml new file mode 100644 index 0000000000000..952f7e98232c0 --- /dev/null +++ b/resource_customizations/external-secrets.io/PushSecret/actions/testdata/push-secret-updated.yaml @@ -0,0 +1,41 @@ +apiVersion: external-secrets.io/v1alpha1 +kind: PushSecret +metadata: + annotations: + force-sync: '0001-01-01T00:00:00Z' + creationTimestamp: '2023-07-05T20:49:16Z' + generation: 1 + name: test-healthy + namespace: external-secret + resourceVersion: '777692391' + uid: 88cb613a-07b0-4fb2-8fdb-d5a5a9c2c917 +spec: + data: + - match: + remoteRef: + property: test + remoteKey: remote/path + secretKey: test + deletionPolicy: None + refreshInterval: 5m + secretStoreRefs: + - kind: ClusterSecretStore + name: my-store + selector: + secret: + name: existing-secret +status: + conditions: + - lastTransitionTime: '2023-07-05T20:49:16Z' + message: PushSecret synced successfully + reason: Synced + status: 'True' + type: Ready + syncedPushSecrets: + ClusterSecretStore/my-store: + remote/path/test: + match: + remoteRef: + property: test + remoteKey: remote/path + secretKey: test diff --git a/resource_customizations/external-secrets.io/PushSecret/actions/testdata/push-secret.yaml b/resource_customizations/external-secrets.io/PushSecret/actions/testdata/push-secret.yaml new file mode 100644 index 0000000000000..487233a773e95 --- /dev/null +++ b/resource_customizations/external-secrets.io/PushSecret/actions/testdata/push-secret.yaml @@ -0,0 +1,39 @@ +apiVersion: external-secrets.io/v1alpha1 +kind: PushSecret +metadata: + creationTimestamp: '2023-07-05T20:49:16Z' + generation: 1 + name: test-healthy + namespace: external-secret + resourceVersion: '777692391' + uid: 88cb613a-07b0-4fb2-8fdb-d5a5a9c2c917 +spec: + data: + - match: + remoteRef: + property: test + remoteKey: remote/path + secretKey: test + deletionPolicy: None + refreshInterval: 5m + secretStoreRefs: + - kind: ClusterSecretStore + name: my-store + selector: + secret: + name: existing-secret +status: + conditions: + - lastTransitionTime: '2023-07-05T20:49:16Z' + message: PushSecret synced successfully + reason: Synced + status: 'True' + type: Ready + syncedPushSecrets: + ClusterSecretStore/my-store: + remote/path/test: + match: + remoteRef: + property: test + remoteKey: remote/path + secretKey: test diff --git a/resource_customizations/external-secrets.io/PushSecret/health.lua b/resource_customizations/external-secrets.io/PushSecret/health.lua new file mode 100644 index 0000000000000..d86cb4c47f8b5 --- /dev/null +++ b/resource_customizations/external-secrets.io/PushSecret/health.lua @@ -0,0 +1,20 @@ +hs = {} +if obj.status ~= nil then + if obj.status.conditions ~= nil then + 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 + return hs + end + if condition.type == "Ready" and condition.status == "True" then + hs.status = "Healthy" + hs.message = condition.message + return hs + end + end + end +end +hs.status = "Progressing" +hs.message = "Waiting for PushSecret" +return hs diff --git a/resource_customizations/external-secrets.io/PushSecret/health_test.yaml b/resource_customizations/external-secrets.io/PushSecret/health_test.yaml new file mode 100644 index 0000000000000..07d6ab3c70136 --- /dev/null +++ b/resource_customizations/external-secrets.io/PushSecret/health_test.yaml @@ -0,0 +1,13 @@ +tests: + - healthStatus: + status: Progressing + message: Waiting for PushSecret + inputPath: testdata/progressing.yaml + - healthStatus: + status: Degraded + message: 'set secret failed: could not write remote ref test to target secretstore my-store: Error making API request.' + inputPath: testdata/degraded.yaml + - healthStatus: + status: Healthy + message: 'PushSecret synced successfully' + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/external-secrets.io/PushSecret/testdata/degraded.yaml b/resource_customizations/external-secrets.io/PushSecret/testdata/degraded.yaml new file mode 100644 index 0000000000000..aab422eb3eb30 --- /dev/null +++ b/resource_customizations/external-secrets.io/PushSecret/testdata/degraded.yaml @@ -0,0 +1,33 @@ +apiVersion: external-secrets.io/v1alpha1 +kind: PushSecret +metadata: + creationTimestamp: '2023-07-05T20:49:16Z' + generation: 1 + name: test-degraded + namespace: external-secret + resourceVersion: '777692391' + uid: 88cb613a-07b0-4fb2-8fdb-d5a5a9c2c917 +spec: + data: + - match: + remoteRef: + property: test + remoteKey: remote/path + secretKey: test + deletionPolicy: None + refreshInterval: 5m + secretStoreRefs: + - kind: ClusterSecretStore + name: my-store + selector: + secret: + name: existing-secret +status: + conditions: + - lastTransitionTime: '2023-07-05T20:49:16Z' + message: 'set secret failed: could not write remote ref test to target secretstore my-store: Error making API request.' + reason: Errored + status: 'False' + type: Ready + syncedPushSecrets: + ClusterSecretStore/my-store: {} diff --git a/resource_customizations/external-secrets.io/PushSecret/testdata/healthy.yaml b/resource_customizations/external-secrets.io/PushSecret/testdata/healthy.yaml new file mode 100644 index 0000000000000..487233a773e95 --- /dev/null +++ b/resource_customizations/external-secrets.io/PushSecret/testdata/healthy.yaml @@ -0,0 +1,39 @@ +apiVersion: external-secrets.io/v1alpha1 +kind: PushSecret +metadata: + creationTimestamp: '2023-07-05T20:49:16Z' + generation: 1 + name: test-healthy + namespace: external-secret + resourceVersion: '777692391' + uid: 88cb613a-07b0-4fb2-8fdb-d5a5a9c2c917 +spec: + data: + - match: + remoteRef: + property: test + remoteKey: remote/path + secretKey: test + deletionPolicy: None + refreshInterval: 5m + secretStoreRefs: + - kind: ClusterSecretStore + name: my-store + selector: + secret: + name: existing-secret +status: + conditions: + - lastTransitionTime: '2023-07-05T20:49:16Z' + message: PushSecret synced successfully + reason: Synced + status: 'True' + type: Ready + syncedPushSecrets: + ClusterSecretStore/my-store: + remote/path/test: + match: + remoteRef: + property: test + remoteKey: remote/path + secretKey: test diff --git a/resource_customizations/external-secrets.io/PushSecret/testdata/progressing.yaml b/resource_customizations/external-secrets.io/PushSecret/testdata/progressing.yaml new file mode 100644 index 0000000000000..e67d679bae123 --- /dev/null +++ b/resource_customizations/external-secrets.io/PushSecret/testdata/progressing.yaml @@ -0,0 +1,24 @@ +apiVersion: external-secrets.io/v1alpha1 +kind: PushSecret +metadata: + creationTimestamp: '2023-07-05T20:49:16Z' + generation: 1 + name: test-progressing + namespace: external-secret + resourceVersion: '777692391' + uid: 88cb613a-07b0-4fb2-8fdb-d5a5a9c2c917 +spec: + data: + - match: + remoteRef: + property: test + remoteKey: remote/path + secretKey: test + deletionPolicy: None + refreshInterval: 5m + secretStoreRefs: + - kind: ClusterSecretStore + name: my-store + selector: + secret: + name: existing-secret diff --git a/resource_customizations/external-secrets.io/SecretStore/health.lua b/resource_customizations/external-secrets.io/SecretStore/health.lua index 5c58908ac6e9f..656c8a3146138 100644 --- a/resource_customizations/external-secrets.io/SecretStore/health.lua +++ b/resource_customizations/external-secrets.io/SecretStore/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do diff --git a/resource_customizations/flagger.app/Canary/health.lua b/resource_customizations/flagger.app/Canary/health.lua index 86872556ed4b5..dd32bbc133e0f 100644 --- a/resource_customizations/flagger.app/Canary/health.lua +++ b/resource_customizations/flagger.app/Canary/health.lua @@ -1,7 +1,7 @@ -sep = " --- " -hs = {} +local sep = " --- " +local hs = {} if obj.status ~= nil then - message = "" + local message = "" if tonumber(obj.status.canaryWeight) > 0 then message = "Canary Weight: " .. obj.status.canaryWeight .. " %" end diff --git a/resource_customizations/flink.apache.org/FlinkDeployment/health.lua b/resource_customizations/flink.apache.org/FlinkDeployment/health.lua index 64c0782209791..677f1a7b87049 100644 --- a/resource_customizations/flink.apache.org/FlinkDeployment/health.lua +++ b/resource_customizations/flink.apache.org/FlinkDeployment/health.lua @@ -1,7 +1,7 @@ -health_status = {} +local health_status = {} if obj.status ~= nil and obj.status.reconciliationStatus ~= nil then - if obj.status.reconciliationStatus.success then + if obj.status.reconciliationStatus.success or obj.status.reconciliationStatus.state == "DEPLOYED" then health_status.status = "Healthy" return health_status end diff --git a/resource_customizations/flink.apache.org/FlinkDeployment/health_test.yaml b/resource_customizations/flink.apache.org/FlinkDeployment/health_test.yaml index 1e8cb55b72769..25a4f1273a5d3 100644 --- a/resource_customizations/flink.apache.org/FlinkDeployment/health_test.yaml +++ b/resource_customizations/flink.apache.org/FlinkDeployment/health_test.yaml @@ -1,10 +1,16 @@ tests: - healthStatus: status: Healthy - inputPath: testdata/healthy_running.yaml + inputPath: testdata/healthy_running_v0.1.x.yaml - healthStatus: status: Healthy - inputPath: testdata/healthy_suspended.yaml + inputPath: testdata/healthy_running_v1.x.yaml +- healthStatus: + status: Healthy + inputPath: testdata/healthy_suspended_v0.1.x.yaml +- healthStatus: + status: Healthy + inputPath: testdata/healthy_suspended_v1.x.yaml - healthStatus: status: Progressing message: Waiting for deploying diff --git a/resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_running.yaml b/resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_running_v0.1.x.yaml similarity index 100% rename from resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_running.yaml rename to resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_running_v0.1.x.yaml diff --git a/resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_running_v1.x.yaml b/resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_running_v1.x.yaml new file mode 100644 index 0000000000000..60e2c2bfa26fc --- /dev/null +++ b/resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_running_v1.x.yaml @@ -0,0 +1,11 @@ +apiVersion: flink.apache.org/v1alpha1 +kind: FlinkDeployment +spec: + job: + state: running +status: + jobManagerDeploymentStatus: READY + jobStatus: + state: RUNNING + reconciliationStatus: + state: DEPLOYED diff --git a/resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_suspended.yaml b/resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_suspended_v0.1.x.yaml similarity index 100% rename from resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_suspended.yaml rename to resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_suspended_v0.1.x.yaml diff --git a/resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_suspended_v1.x.yaml b/resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_suspended_v1.x.yaml new file mode 100644 index 0000000000000..023c2899fb60d --- /dev/null +++ b/resource_customizations/flink.apache.org/FlinkDeployment/testdata/healthy_suspended_v1.x.yaml @@ -0,0 +1,11 @@ +apiVersion: flink.apache.org/v1alpha1 +kind: FlinkDeployment +spec: + job: + state: suspended +status: + jobManagerDeploymentStatus: MISSING + jobStatus: + state: SUSPENDED + reconciliationStatus: + state: DEPLOYED diff --git a/resource_customizations/iam.cnrm.cloud.google.com/IAMPartialPolicy/health.lua b/resource_customizations/iam.cnrm.cloud.google.com/IAMPartialPolicy/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/iam.cnrm.cloud.google.com/IAMPartialPolicy/health.lua +++ b/resource_customizations/iam.cnrm.cloud.google.com/IAMPartialPolicy/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/iam.cnrm.cloud.google.com/IAMPolicy/health.lua b/resource_customizations/iam.cnrm.cloud.google.com/IAMPolicy/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/iam.cnrm.cloud.google.com/IAMPolicy/health.lua +++ b/resource_customizations/iam.cnrm.cloud.google.com/IAMPolicy/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/iam.cnrm.cloud.google.com/IAMPolicyMember/health.lua b/resource_customizations/iam.cnrm.cloud.google.com/IAMPolicyMember/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/iam.cnrm.cloud.google.com/IAMPolicyMember/health.lua +++ b/resource_customizations/iam.cnrm.cloud.google.com/IAMPolicyMember/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/iam.cnrm.cloud.google.com/IAMServiceAccount/health.lua b/resource_customizations/iam.cnrm.cloud.google.com/IAMServiceAccount/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/iam.cnrm.cloud.google.com/IAMServiceAccount/health.lua +++ b/resource_customizations/iam.cnrm.cloud.google.com/IAMServiceAccount/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/iammanager.keikoproj.io/Iamrole/health.lua b/resource_customizations/iammanager.keikoproj.io/Iamrole/health.lua new file mode 100644 index 0000000000000..0b89687e08637 --- /dev/null +++ b/resource_customizations/iammanager.keikoproj.io/Iamrole/health.lua @@ -0,0 +1,33 @@ +local hs = {} +if obj.status ~= nil then + -- Each message may or may not use these. + local roleName = obj.status.roleName or "" + local roleARN = obj.status.roleARN or "" + local roleID = obj.status.roleID or "" + + if obj.status.state == "Ready" then + hs.status = "Healthy" + hs.message = "Role '" .. roleName .. "' exists with ARN '" .. roleARN .. "' and ID '" .. roleID .. "'." + return hs + end + + local message = "" + -- Current non-ready statuses: https://github.com/keikoproj/iam-manager/blob/3aeb2f8ec3005e1c53a057b3b0f79e14a0e5b9cb/api/v1alpha1/iamrole_types.go#L150-L156 + if obj.status.state == "Error" or obj.status.state == "RolesMaxLimitReached" or obj.status.state == "PolicyNotAllowed" or obj.status.state == "RoleNameNotAvailable" then + hs.status = "Degraded" + message = "Failed to reconcile the Iamrole " + if obj.status.retryCount ~= nil and obj.status.retryCount > 0 then + message = message .. "(retry " .. tostring(obj.status.retryCount) .. ") " + end + message = message .. "for role '" .. roleName .. "' with ARN '" .. roleARN .. "' and ID '" .. roleID .. "'." + if obj.status.errorDescription ~= nil then + message = message .. " Reconciliation error was: " .. obj.status.errorDescription + end + hs.message = message + return hs + end +end + +hs.status = "Progressing" +hs.message = "Waiting for Iamrole to be reconciled" +return hs diff --git a/resource_customizations/iammanager.keikoproj.io/Iamrole/health_test.yaml b/resource_customizations/iammanager.keikoproj.io/Iamrole/health_test.yaml new file mode 100644 index 0000000000000..660276f41f475 --- /dev/null +++ b/resource_customizations/iammanager.keikoproj.io/Iamrole/health_test.yaml @@ -0,0 +1,20 @@ +tests: +- healthStatus: + status: Degraded + message: |- + Failed to reconcile the Iamrole (retry 1) for role 'k8s-test' with ARN 'arn:aws:iam::111111111111:role/k8s-test' and ID 'ABCDEFGHIJKLMNOPQRSTU'. Reconciliation error was: NoSuchEntity: The role with name k8s-test cannot be found. + status code: 404, request id: f80c99fc-c78d-4b1c-806d-3a162fbbc900 + inputPath: testdata/degraded_error.yaml +- healthStatus: + status: Degraded + message: |- + Failed to reconcile the Iamrole for role 'k8s-test' with ARN '' and ID ''. Reconciliation error was: maximum number of allowed roles reached. You must delete any existing role before proceeding further + inputPath: testdata/degraded_rolesMaxLimitReached.yaml +- healthStatus: + status: Healthy + message: Role 'k8s-test' exists with ARN 'arn:aws:iam::111111111111:role/k8s-test' and ID 'ABCDEFGHIJKLMNOPQRSTU'. + inputPath: testdata/healthy.yaml +- healthStatus: + status: Progressing + message: 'Waiting for Iamrole to be reconciled' + inputPath: testdata/progressing_noStatus.yaml diff --git a/resource_customizations/iammanager.keikoproj.io/Iamrole/testdata/degraded_error.yaml b/resource_customizations/iammanager.keikoproj.io/Iamrole/testdata/degraded_error.yaml new file mode 100644 index 0000000000000..3bf3e7cee2b85 --- /dev/null +++ b/resource_customizations/iammanager.keikoproj.io/Iamrole/testdata/degraded_error.yaml @@ -0,0 +1,29 @@ +apiVersion: iammanager.keikoproj.io/v1alpha1 +kind: Iamrole +metadata: + finalizers: + - iamrole.finalizers.iammanager.keikoproj.io + name: iamrole + namespace: test +spec: + PolicyDocument: + Statement: + - Action: + - ec2:* + Effect: Deny + Resource: + - '*' + - Action: + - iam:* + Effect: Deny + Resource: + - '*' +status: + errorDescription: "NoSuchEntity: The role with name k8s-test cannot + be found.\n\tstatus code: 404, request id: f80c99fc-c78d-4b1c-806d-3a162fbbc900" + lastUpdatedTimestamp: "2023-10-10T19:31:06Z" + retryCount: 1 + roleARN: arn:aws:iam::111111111111:role/k8s-test + roleID: ABCDEFGHIJKLMNOPQRSTU + roleName: k8s-test + state: Error diff --git a/resource_customizations/iammanager.keikoproj.io/Iamrole/testdata/degraded_rolesMaxLimitReached.yaml b/resource_customizations/iammanager.keikoproj.io/Iamrole/testdata/degraded_rolesMaxLimitReached.yaml new file mode 100644 index 0000000000000..906c72083bede --- /dev/null +++ b/resource_customizations/iammanager.keikoproj.io/Iamrole/testdata/degraded_rolesMaxLimitReached.yaml @@ -0,0 +1,26 @@ +apiVersion: iammanager.keikoproj.io/v1alpha1 +kind: Iamrole +metadata: + finalizers: + - iamrole.finalizers.iammanager.keikoproj.io + name: iamrole + namespace: test +spec: + PolicyDocument: + Statement: + - Action: + - ec2:* + Effect: Deny + Resource: + - '*' + - Action: + - iam:* + Effect: Deny + Resource: + - '*' +status: + errorDescription: maximum number of allowed roles reached. You must delete any existing role before proceeding further + lastUpdatedTimestamp: "2023-10-10T19:25:26Z" + retryCount: 0 + roleName: k8s-test + state: RolesMaxLimitReached diff --git a/resource_customizations/iammanager.keikoproj.io/Iamrole/testdata/healthy.yaml b/resource_customizations/iammanager.keikoproj.io/Iamrole/testdata/healthy.yaml new file mode 100644 index 0000000000000..273cf3a571234 --- /dev/null +++ b/resource_customizations/iammanager.keikoproj.io/Iamrole/testdata/healthy.yaml @@ -0,0 +1,27 @@ +apiVersion: iammanager.keikoproj.io/v1alpha1 +kind: Iamrole +metadata: + finalizers: + - iamrole.finalizers.iammanager.keikoproj.io + name: iamrole + namespace: default +spec: + PolicyDocument: + Statement: + - Action: + - 'ec2:*' + Effect: Deny + Resource: + - '*' + - Action: + - 'iam:*' + Effect: Deny + Resource: + - '*' +status: + lastUpdatedTimestamp: '2023-10-10T20:36:23Z' + retryCount: 0 + roleARN: 'arn:aws:iam::111111111111:role/k8s-test' + roleID: ABCDEFGHIJKLMNOPQRSTU + roleName: k8s-test + state: Ready diff --git a/resource_customizations/iammanager.keikoproj.io/Iamrole/testdata/progressing_noStatus.yaml b/resource_customizations/iammanager.keikoproj.io/Iamrole/testdata/progressing_noStatus.yaml new file mode 100644 index 0000000000000..29c18a4c0380a --- /dev/null +++ b/resource_customizations/iammanager.keikoproj.io/Iamrole/testdata/progressing_noStatus.yaml @@ -0,0 +1,20 @@ +apiVersion: iammanager.keikoproj.io/v1alpha1 +kind: Iamrole +metadata: + finalizers: + - iamrole.finalizers.iammanager.keikoproj.io + name: iamrole + namespace: default +spec: + PolicyDocument: + Statement: + - Action: + - 'ec2:*' + Effect: Deny + Resource: + - '*' + - Action: + - 'iam:*' + Effect: Deny + Resource: + - '*' diff --git a/resource_customizations/install.istio.io/IstioOperator/health.lua b/resource_customizations/install.istio.io/IstioOperator/health.lua index e2538dec24d57..874ff3cdd3351 100644 --- a/resource_customizations/install.istio.io/IstioOperator/health.lua +++ b/resource_customizations/install.istio.io/IstioOperator/health.lua @@ -1,4 +1,4 @@ -health_status = {} +local health_status = {} if obj.status ~= nil then if obj.status.status ~= nil then if obj.status.status == 0 or obj.status.status == "NONE" then diff --git a/resource_customizations/jaegertracing.io/Jaeger/health.lua b/resource_customizations/jaegertracing.io/Jaeger/health.lua index 71f10438ce9fe..b7514d53065db 100644 --- a/resource_customizations/jaegertracing.io/Jaeger/health.lua +++ b/resource_customizations/jaegertracing.io/Jaeger/health.lua @@ -1,4 +1,4 @@ -health_status = {} +local health_status = {} if obj.status ~= nil then if obj.status.phase == "Running" then health_status.status = "Healthy" diff --git a/resource_customizations/kafka.banzaicloud.io/KafkaCluster/health.lua b/resource_customizations/kafka.banzaicloud.io/KafkaCluster/health.lua index 06082dae24425..7422fd4104727 100644 --- a/resource_customizations/kafka.banzaicloud.io/KafkaCluster/health.lua +++ b/resource_customizations/kafka.banzaicloud.io/KafkaCluster/health.lua @@ -1,22 +1,17 @@ -health_status = {} +local health_status = {} if obj.status ~= nil then if obj.status.brokersState ~= nil then - counter = 0 - 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/kafka.strimzi.io/Kafka/health.lua b/resource_customizations/kafka.strimzi.io/Kafka/health.lua index 759f94a2cdcf8..346a18114f84d 100644 --- a/resource_customizations/kafka.strimzi.io/Kafka/health.lua +++ b/resource_customizations/kafka.strimzi.io/Kafka/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do diff --git a/resource_customizations/kafka.strimzi.io/Kafka/health_test.yaml b/resource_customizations/kafka.strimzi.io/Kafka/health_test.yaml index 9c7d7bc31fe45..0038036e84a47 100644 --- a/resource_customizations/kafka.strimzi.io/Kafka/health_test.yaml +++ b/resource_customizations/kafka.strimzi.io/Kafka/health_test.yaml @@ -5,7 +5,6 @@ tests: inputPath: testdata/progressing_noStatus.yaml - healthStatus: status: Degraded - message: "Error" message: "Exceeded timeout of 300000ms while waiting for StatefulSet resource my-cluster-zookeeper in namespace default to be ready" inputPath: testdata/degraded.yaml - healthStatus: diff --git a/resource_customizations/kafka.strimzi.io/KafkaConnect/health.lua b/resource_customizations/kafka.strimzi.io/KafkaConnect/health.lua index f12158def6798..8cd15dd14c6e7 100644 --- a/resource_customizations/kafka.strimzi.io/KafkaConnect/health.lua +++ b/resource_customizations/kafka.strimzi.io/KafkaConnect/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do diff --git a/resource_customizations/kafka.strimzi.io/KafkaConnect/testdata/degraded.yaml b/resource_customizations/kafka.strimzi.io/KafkaConnect/testdata/degraded.yaml index 14294958aa2c8..b7c9d15cd3dbb 100644 --- a/resource_customizations/kafka.strimzi.io/KafkaConnect/testdata/degraded.yaml +++ b/resource_customizations/kafka.strimzi.io/KafkaConnect/testdata/degraded.yaml @@ -81,7 +81,7 @@ spec: operator: In values: - kafka-connect - topologyKey: failure-domain.beta.kubernetes.io/zone + topologyKey: topology.kubernetes.io/zone weight: 100 metadata: annotations: diff --git a/resource_customizations/kafka.strimzi.io/KafkaConnect/testdata/healthy.yaml b/resource_customizations/kafka.strimzi.io/KafkaConnect/testdata/healthy.yaml index 7197050e30f35..1d03d3b5c95c8 100644 --- a/resource_customizations/kafka.strimzi.io/KafkaConnect/testdata/healthy.yaml +++ b/resource_customizations/kafka.strimzi.io/KafkaConnect/testdata/healthy.yaml @@ -81,7 +81,7 @@ spec: operator: In values: - kafka-connect - topologyKey: failure-domain.beta.kubernetes.io/zone + topologyKey: topology.kubernetes.io/zone weight: 100 metadata: annotations: diff --git a/resource_customizations/kafka.strimzi.io/KafkaConnect/testdata/progressing_noStatus.yaml b/resource_customizations/kafka.strimzi.io/KafkaConnect/testdata/progressing_noStatus.yaml index 7c1c7255f158a..7f218527ff13f 100644 --- a/resource_customizations/kafka.strimzi.io/KafkaConnect/testdata/progressing_noStatus.yaml +++ b/resource_customizations/kafka.strimzi.io/KafkaConnect/testdata/progressing_noStatus.yaml @@ -81,7 +81,7 @@ spec: operator: In values: - kafka-connect - topologyKey: failure-domain.beta.kubernetes.io/zone + topologyKey: topology.kubernetes.io/zone weight: 100 metadata: annotations: @@ -93,4 +93,4 @@ spec: - effect: NoSchedule key: dynamic-node operator: Equal - value: "true" \ No newline at end of file + value: "true" diff --git a/resource_customizations/kafka.strimzi.io/KafkaTopic/health.lua b/resource_customizations/kafka.strimzi.io/KafkaTopic/health.lua index 36509c7614f66..2d3ada3eac1e9 100644 --- a/resource_customizations/kafka.strimzi.io/KafkaTopic/health.lua +++ b/resource_customizations/kafka.strimzi.io/KafkaTopic/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do diff --git a/resource_customizations/kafka.strimzi.io/KafkaUser/health.lua b/resource_customizations/kafka.strimzi.io/KafkaUser/health.lua index ad25d41497027..44172d1e38105 100644 --- a/resource_customizations/kafka.strimzi.io/KafkaUser/health.lua +++ b/resource_customizations/kafka.strimzi.io/KafkaUser/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do diff --git a/resource_customizations/kiali.io/Kiali/health.lua b/resource_customizations/kiali.io/Kiali/health.lua index 6820b121a0f68..ea066cf88882f 100644 --- a/resource_customizations/kiali.io/Kiali/health.lua +++ b/resource_customizations/kiali.io/Kiali/health.lua @@ -1,4 +1,4 @@ -health_status = {} +local health_status = {} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do diff --git a/resource_customizations/kubernetes-client.io/ExternalSecret/health.lua b/resource_customizations/kubernetes-client.io/ExternalSecret/health.lua index 697a0b91ee60d..8e4109158e94f 100644 --- a/resource_customizations/kubernetes-client.io/ExternalSecret/health.lua +++ b/resource_customizations/kubernetes-client.io/ExternalSecret/health.lua @@ -1,4 +1,4 @@ -health_status = {} +local health_status = {} if obj.status ~= nil then if obj.status.status == "SUCCESS" then health_status.status = "Healthy" diff --git a/resource_customizations/kubevirt.io/VirtualMachine/health.lua b/resource_customizations/kubevirt.io/VirtualMachine/health.lua index d9e0ebdd96e51..6c0d63348b766 100644 --- a/resource_customizations/kubevirt.io/VirtualMachine/health.lua +++ b/resource_customizations/kubevirt.io/VirtualMachine/health.lua @@ -1,4 +1,4 @@ -hs = { status="Progressing", message="No status available"} +local hs = { status="Progressing", message="No status available"} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do @@ -13,7 +13,7 @@ if obj.status ~= nil then hs.message="Running" else if obj.status.created then - hs.message = "Starting" + hs.message = "Starting" else hs.status = "Suspended" hs.message = "Stopped" diff --git a/resource_customizations/kubevirt.io/VirtualMachineInstance/health.lua b/resource_customizations/kubevirt.io/VirtualMachineInstance/health.lua index 30264cf007c6d..27352077786f7 100644 --- a/resource_customizations/kubevirt.io/VirtualMachineInstance/health.lua +++ b/resource_customizations/kubevirt.io/VirtualMachineInstance/health.lua @@ -1,4 +1,4 @@ -hs = { status="Progressing", message="No status available"} +local hs = { status="Progressing", message="No status available"} if obj.status ~= nil then if obj.status.phase ~= nil then hs.message = obj.status.phase diff --git a/resource_customizations/lifecycle.keptn.sh/KeptnAppVersion/health.lua b/resource_customizations/lifecycle.keptn.sh/KeptnAppVersion/health.lua index daf3168907672..d99bf033981eb 100644 --- a/resource_customizations/lifecycle.keptn.sh/KeptnAppVersion/health.lua +++ b/resource_customizations/lifecycle.keptn.sh/KeptnAppVersion/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status.status == "Succeeded" then hs.status = "Healthy" hs.message = "KeptnAppVersion is healthy" diff --git a/resource_customizations/lifecycle.keptn.sh/KeptnEvaluation/health.lua b/resource_customizations/lifecycle.keptn.sh/KeptnEvaluation/health.lua index 2ea65e96736f2..97543ecc2b999 100644 --- a/resource_customizations/lifecycle.keptn.sh/KeptnEvaluation/health.lua +++ b/resource_customizations/lifecycle.keptn.sh/KeptnEvaluation/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status.overallStatus == "Succeeded" then hs.status = "Healthy" hs.message = "KeptnEvaluation is healthy" diff --git a/resource_customizations/lifecycle.keptn.sh/KeptnTask/health.lua b/resource_customizations/lifecycle.keptn.sh/KeptnTask/health.lua index e22de12347391..d8c6047679195 100644 --- a/resource_customizations/lifecycle.keptn.sh/KeptnTask/health.lua +++ b/resource_customizations/lifecycle.keptn.sh/KeptnTask/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status.status == "Succeeded" then hs.status = "Healthy" hs.message = "KeptnTask is healthy" diff --git a/resource_customizations/lifecycle.keptn.sh/KeptnWorkloadInstance/health.lua b/resource_customizations/lifecycle.keptn.sh/KeptnWorkloadInstance/health.lua index 64002013a273f..5ce79d0448779 100644 --- a/resource_customizations/lifecycle.keptn.sh/KeptnWorkloadInstance/health.lua +++ b/resource_customizations/lifecycle.keptn.sh/KeptnWorkloadInstance/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status.status == "Succeeded" then hs.status = "Healthy" hs.message = "KeptnWorkloadInstance is healthy" diff --git a/resource_customizations/mariadb.mmontes.io/MariaDB/health.lua b/resource_customizations/mariadb.mmontes.io/MariaDB/health.lua new file mode 100644 index 0000000000000..b0278bb22650e --- /dev/null +++ b/resource_customizations/mariadb.mmontes.io/MariaDB/health.lua @@ -0,0 +1,25 @@ +local health_status = {} + +if obj.status ~= nil and obj.status.conditions ~= nil then + + for i, condition in ipairs(obj.status.conditions) do + + health_status.message = condition.message + + if condition.status == "False" then + if condition.reason == "Failed" then + health_status.status = "Degraded" + return health_status + end + health_status.status = "Progressing" + return health_status + end + end + + health_status.status = "Healthy" + return health_status +end + +health_status.status = "Progressing" +health_status.message = "No status info available" +return health_status diff --git a/resource_customizations/mariadb.mmontes.io/MariaDB/health_test.yaml b/resource_customizations/mariadb.mmontes.io/MariaDB/health_test.yaml new file mode 100644 index 0000000000000..f3dba1ac80c58 --- /dev/null +++ b/resource_customizations/mariadb.mmontes.io/MariaDB/health_test.yaml @@ -0,0 +1,25 @@ +tests: +- healthStatus: + status: Progressing + message: "No status info available" + inputPath: testdata/no_status.yaml +- healthStatus: + status: Healthy + message: "Running" + inputPath: testdata/statefulset_ready.yaml +- healthStatus: + status: Progressing + message: "Not ready" + inputPath: testdata/statefulset_not_ready.yaml +- healthStatus: + status: Healthy + message: "Running" + inputPath: testdata/restore_complete.yaml +- healthStatus: + status: Progressing + message: "Restoring backup" + inputPath: testdata/restore_not_complete.yaml +- healthStatus: + status: Degraded + message: "Error creating ConfigMap" + inputPath: testdata/mariadb_error.yaml diff --git a/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/mariadb_error.yaml b/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/mariadb_error.yaml new file mode 100644 index 0000000000000..030391dda7acc --- /dev/null +++ b/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/mariadb_error.yaml @@ -0,0 +1,27 @@ +apiVersion: mariadb.mmontes.io/v1alpha1 +kind: MariaDB +metadata: + name: mariadb-server +spec: + rootPasswordSecretKeyRef: + name: mariadb + key: root-password + image: + repository: mariadb + tag: "10.7.4" + pullPolicy: IfNotPresent + port: 3306 + volumeClaimTemplate: + resources: + requests: + storage: 100Mi + storageClassName: standard + accessModes: + - ReadWriteOnce +status: + conditions: + - lastTransitionTime: '2023-04-20T15:31:15Z' + message: Error creating ConfigMap + reason: Failed + status: 'False' + type: Ready diff --git a/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/no_status.yaml b/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/no_status.yaml new file mode 100644 index 0000000000000..276d09b04c272 --- /dev/null +++ b/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/no_status.yaml @@ -0,0 +1,22 @@ +apiVersion: mariadb.mmontes.io/v1alpha1 +kind: MariaDB +metadata: + name: mariadb-server +spec: + rootPasswordSecretKeyRef: + name: mariadb + key: root-password + image: + repository: mariadb + tag: "10.7.4" + pullPolicy: IfNotPresent + port: 3306 + volumeClaimTemplate: + resources: + requests: + storage: 100Mi + storageClassName: standard + accessModes: + - ReadWriteOnce +status: + revision: 0 diff --git a/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/restore_complete.yaml b/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/restore_complete.yaml new file mode 100644 index 0000000000000..7a9358c0f16d6 --- /dev/null +++ b/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/restore_complete.yaml @@ -0,0 +1,32 @@ +apiVersion: mariadb.mmontes.io/v1alpha1 +kind: MariaDB +metadata: + name: mariadb-server +spec: + rootPasswordSecretKeyRef: + name: mariadb + key: root-password + image: + repository: mariadb + tag: "10.7.4" + pullPolicy: IfNotPresent + port: 3306 + volumeClaimTemplate: + resources: + requests: + storage: 100Mi + storageClassName: standard + accessModes: + - ReadWriteOnce +status: + conditions: + - lastTransitionTime: "2023-04-05T14:18:01Z" + message: Ready + reason: RestoreComplete + status: "True" + type: Bootstrapped + - lastTransitionTime: "2023-04-05T14:18:02Z" + message: Running + reason: RestoreComplete + status: "True" + type: Ready diff --git a/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/restore_not_complete.yaml b/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/restore_not_complete.yaml new file mode 100644 index 0000000000000..a3f600eae96a2 --- /dev/null +++ b/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/restore_not_complete.yaml @@ -0,0 +1,32 @@ +apiVersion: mariadb.mmontes.io/v1alpha1 +kind: MariaDB +metadata: + name: mariadb-server +spec: + rootPasswordSecretKeyRef: + name: mariadb + key: root-password + image: + repository: mariadb + tag: "10.7.4" + pullPolicy: IfNotPresent + port: 3306 + volumeClaimTemplate: + resources: + requests: + storage: 100Mi + storageClassName: standard + accessModes: + - ReadWriteOnce +status: + conditions: + - lastTransitionTime: "2023-04-05T14:18:01Z" + message: Restoring backup + reason: RestoreNotComplete + status: "False" + type: Ready + - lastTransitionTime: "2023-04-05T14:18:02Z" + message: Not ready + reason: RestoreNotComplete + status: "False" + type: Bootstrapped diff --git a/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/statefulset_not_ready.yaml b/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/statefulset_not_ready.yaml new file mode 100644 index 0000000000000..96d46b4bf61fe --- /dev/null +++ b/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/statefulset_not_ready.yaml @@ -0,0 +1,27 @@ +apiVersion: mariadb.mmontes.io/v1alpha1 +kind: MariaDB +metadata: + name: mariadb-server +spec: + rootPasswordSecretKeyRef: + name: mariadb + key: root-password + image: + repository: mariadb + tag: "10.7.4" + pullPolicy: IfNotPresent + port: 3306 + volumeClaimTemplate: + resources: + requests: + storage: 100Mi + storageClassName: standard + accessModes: + - ReadWriteOnce +status: + conditions: + - lastTransitionTime: "2023-04-05T14:18:01Z" + message: Not ready + reason: StatefulSetNotReady + status: "False" + type: Ready diff --git a/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/statefulset_ready.yaml b/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/statefulset_ready.yaml new file mode 100644 index 0000000000000..e4870b0064dbb --- /dev/null +++ b/resource_customizations/mariadb.mmontes.io/MariaDB/testdata/statefulset_ready.yaml @@ -0,0 +1,27 @@ +apiVersion: mariadb.mmontes.io/v1alpha1 +kind: MariaDB +metadata: + name: mariadb-server +spec: + rootPasswordSecretKeyRef: + name: mariadb + key: root-password + image: + repository: mariadb + tag: "10.7.4" + pullPolicy: IfNotPresent + port: 3306 + volumeClaimTemplate: + resources: + requests: + storage: 100Mi + storageClassName: standard + accessModes: + - ReadWriteOnce +status: + conditions: + - lastTransitionTime: "2023-04-05T14:18:01Z" + message: Running + reason: StatefulSetReady + status: "True" + type: Ready diff --git a/resource_customizations/minio.min.io/Tenant/health.lua b/resource_customizations/minio.min.io/Tenant/health.lua index 088d70a5ecf4f..a62e3d2670a19 100644 --- a/resource_customizations/minio.min.io/Tenant/health.lua +++ b/resource_customizations/minio.min.io/Tenant/health.lua @@ -1,4 +1,4 @@ -health_status = {} +local health_status = {} if obj.status ~= nil then if obj.status.currentState ~= nil then if obj.status.currentState == "Initialized" then diff --git a/resource_customizations/monitoring.coreos.com/Prometheus/health.lua b/resource_customizations/monitoring.coreos.com/Prometheus/health.lua index 34fddd1393970..b0b052cf93673 100644 --- a/resource_customizations/monitoring.coreos.com/Prometheus/health.lua +++ b/resource_customizations/monitoring.coreos.com/Prometheus/health.lua @@ -1,4 +1,4 @@ -hs={ status = "Progressing", message = "Waiting for initialization" } +local hs={ status = "Progressing", message = "Waiting for initialization" } if obj.status ~= nil then if obj.status.conditions ~= nil then diff --git a/resource_customizations/networking.gke.io/ManagedCertificate/health.lua b/resource_customizations/networking.gke.io/ManagedCertificate/health.lua index 9f0f3e127f3f0..b46263f187a27 100644 --- a/resource_customizations/networking.gke.io/ManagedCertificate/health.lua +++ b/resource_customizations/networking.gke.io/ManagedCertificate/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.domainStatus ~= nil then diff --git a/resource_customizations/onepassword.com/OnePasswordItem/health.lua b/resource_customizations/onepassword.com/OnePasswordItem/health.lua index ee46c99782136..bce3f068ab9b9 100644 --- a/resource_customizations/onepassword.com/OnePasswordItem/health.lua +++ b/resource_customizations/onepassword.com/OnePasswordItem/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then for i, condition in ipairs(obj.status.conditions) do diff --git a/resource_customizations/operator.knative.dev/KnativeEventing/health.lua b/resource_customizations/operator.knative.dev/KnativeEventing/health.lua index f9cb10370ba9a..aadf6cac3f8a8 100644 --- a/resource_customizations/operator.knative.dev/KnativeEventing/health.lua +++ b/resource_customizations/operator.knative.dev/KnativeEventing/health.lua @@ -1,9 +1,9 @@ -health_status = {} +local health_status = {} if obj.status ~= nil then if obj.status.conditions ~= nil then - numTrue = 0 - numFalse = 0 - msg = "" + local numTrue = 0 + local numFalse = 0 + local msg = "" for i, condition in pairs(obj.status.conditions) do msg = msg .. i .. ": " .. condition.type .. " | " .. condition.status .. "\n" if condition.type == "Ready" and condition.status == "True" then diff --git a/resource_customizations/operator.knative.dev/KnativeServing/health.lua b/resource_customizations/operator.knative.dev/KnativeServing/health.lua index 9903f98ee3788..e412a159634ca 100644 --- a/resource_customizations/operator.knative.dev/KnativeServing/health.lua +++ b/resource_customizations/operator.knative.dev/KnativeServing/health.lua @@ -1,9 +1,9 @@ -health_status = {} +local health_status = {} if obj.status ~= nil then if obj.status.conditions ~= nil then - numTrue = 0 - numFalse = 0 - msg = "" + local numTrue = 0 + local numFalse = 0 + local msg = "" for i, condition in pairs(obj.status.conditions) do msg = msg .. i .. ": " .. condition.type .. " | " .. condition.status .. "\n" if condition.type == "Ready" and condition.status == "True" then diff --git a/resource_customizations/operator.openshift.io/IngressController/health.lua b/resource_customizations/operator.openshift.io/IngressController/health.lua new file mode 100644 index 0000000000000..837a82e980fb0 --- /dev/null +++ b/resource_customizations/operator.openshift.io/IngressController/health.lua @@ -0,0 +1,31 @@ +-- healthcheck for IngressController resources +local hs = {} +if obj.status ~= nil then + if obj.status.conditions ~= nil then + -- if the status conditions are present, iterate over them and check their status + for _, condition in pairs(obj.status.conditions) do + if condition.type == "Degraded" and condition.status == "True" then + hs.status = "Degraded" + hs.message = condition.message + return hs + elseif condition.type == "DeploymentReplicasAllAvailable" and condition.status == "False" then + hs.status = "Progressing" + hs.message = condition.message + return hs + elseif condition.type == "Progressing" and condition.status == "True" then + hs.status = "Progressing" + hs.message = condition.reason + return hs + elseif condition.type == "Available" and condition.status == "True" then + hs.status = "Healthy" + hs.message = "IngressController is available" + return hs + end + end + end +end + +-- default status when none of the previous condition matches +hs.status = "Progressing" +hs.message = "Status of IngressController is not known yet" +return hs diff --git a/resource_customizations/operator.openshift.io/IngressController/health_test.yaml b/resource_customizations/operator.openshift.io/IngressController/health_test.yaml new file mode 100644 index 0000000000000..761d0d6e8fac1 --- /dev/null +++ b/resource_customizations/operator.openshift.io/IngressController/health_test.yaml @@ -0,0 +1,17 @@ +tests: +- healthStatus: + status: Progressing + message: "Status of IngressController is not known yet" + inputPath: testdata/progressing_initialization.yaml +- healthStatus: + status: Progressing + message: "0/1 of replicas are available" + inputPath: testdata/progressing_pod_rollout.yaml +- healthStatus: + status: Degraded + message: "One or more other status conditions indicate a degraded state." + inputPath: testdata/degraded.yaml +- healthStatus: + status: Healthy + message: "IngressController is available" + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/operator.openshift.io/IngressController/testdata/degraded.yaml b/resource_customizations/operator.openshift.io/IngressController/testdata/degraded.yaml new file mode 100644 index 0000000000000..73c7c89e370a9 --- /dev/null +++ b/resource_customizations/operator.openshift.io/IngressController/testdata/degraded.yaml @@ -0,0 +1,103 @@ +--- +apiVersion: operator.openshift.io/v1 +kind: IngressController +metadata: + name: default + namespace: openshift-ingress-operator +spec: + domain: openshift.example.com + endpointPublishingStrategy: + hostNetwork: + httpPort: 80 + httpsPort: 443 + statsPort: 1936 + type: HostNetwork + nodePlacement: + nodeSelector: + matchLabels: + node-role.kubernetes.io/worker: "" + replicas: 1 +status: + availableReplicas: 0 + conditions: + - lastTransitionTime: "2023-01-28T10:05:06Z" + reason: Valid + status: "True" + type: Admitted + - lastTransitionTime: "2023-01-28T10:09:15Z" + status: "True" + type: PodsScheduled + - lastTransitionTime: "2023-01-28T10:05:06Z" + message: The configured endpoint publishing strategy does not include a managed + load balancer + reason: EndpointPublishingStrategyExcludesManagedLoadBalancer + status: "False" + type: LoadBalancerManaged + - lastTransitionTime: "2023-01-28T10:05:06Z" + message: No DNS zones are defined in the cluster dns config. + reason: NoDNSZones + status: "False" + type: DNSManaged + - lastTransitionTime: "2023-01-28T10:05:06Z" + status: "False" + type: Progressing + - lastTransitionTime: "2023-01-28T10:13:55Z" + message: "One or more other status conditions indicate a degraded state." + # message: 'One or more other status conditions indicate a degraded state: CanaryChecksSucceeding=False + # (CanaryChecksRepetitiveFailures: Canary route checks for the default ingress + # controller are failing)' + reason: DegradedConditions + status: "True" + type: Degraded + - lastTransitionTime: "2023-01-28T10:05:06Z" + message: IngressController is upgradeable. + reason: Upgradeable + status: "True" + type: Upgradeable + - lastTransitionTime: "2023-01-28T10:12:55Z" + message: Canary route checks for the default ingress controller are failing + reason: CanaryChecksRepetitiveFailures + status: "False" + type: CanaryChecksSucceeding + domain: openshift.example.com + endpointPublishingStrategy: + hostNetwork: + httpPort: 80 + httpsPort: 443 + protocol: TCP + statsPort: 1936 + type: HostNetwork + namespaceSelector: {} + observedGeneration: 2 + routeSelector: {} + selector: ingresscontroller.operator.openshift.io/deployment-ingresscontroller=default + tlsProfile: + ciphers: + - ECDHE-ECDSA-CHACHA20-POLY1305 + - ECDHE-RSA-CHACHA20-POLY1305 + - ECDHE-ECDSA-AES128-GCM-SHA256 + - ECDHE-RSA-AES128-GCM-SHA256 + - ECDHE-ECDSA-AES256-GCM-SHA384 + - ECDHE-RSA-AES256-GCM-SHA384 + - DHE-RSA-AES128-GCM-SHA256 + - DHE-RSA-AES256-GCM-SHA384 + - ECDHE-ECDSA-AES128-SHA256 + - ECDHE-RSA-AES128-SHA256 + - ECDHE-ECDSA-AES128-SHA + - ECDHE-RSA-AES256-SHA384 + - ECDHE-RSA-AES128-SHA + - ECDHE-ECDSA-AES256-SHA384 + - ECDHE-ECDSA-AES256-SHA + - ECDHE-RSA-AES256-SHA + - DHE-RSA-AES128-SHA256 + - DHE-RSA-AES128-SHA + - DHE-RSA-AES256-SHA256 + - DHE-RSA-AES256-SHA + - AES128-GCM-SHA256 + - AES256-GCM-SHA384 + - AES128-SHA256 + - AES256-SHA256 + - AES128-SHA + - AES256-SHA + - '!DSS' + minTLSVersion: VersionTLS11 diff --git a/resource_customizations/operator.openshift.io/IngressController/testdata/healthy.yaml b/resource_customizations/operator.openshift.io/IngressController/testdata/healthy.yaml new file mode 100644 index 0000000000000..4c7ad766f1d86 --- /dev/null +++ b/resource_customizations/operator.openshift.io/IngressController/testdata/healthy.yaml @@ -0,0 +1,93 @@ +--- +apiVersion: operator.openshift.io/v1 +kind: IngressController +metadata: + name: apps-shard-2 + namespace: openshift-ingress-operator +spec: + domain: openshift-apps-shard-2.example.com + endpointPublishingStrategy: + hostNetwork: + httpPort: 80 + httpsPort: 443 + statsPort: 1936 + type: HostNetwork + nodePlacement: + nodeSelector: + matchLabels: + node-role.kubernetes.io/worker: "" + replicas: 1 +status: + availableReplicas: 1 + conditions: + - lastTransitionTime: "2023-01-28T09:34:36Z" + reason: Valid + status: "True" + type: Admitted + - lastTransitionTime: "2023-01-28T09:43:42Z" + status: "True" + type: PodsScheduled + - lastTransitionTime: "2023-01-28T09:34:36Z" + message: The deployment has Available status condition set to True + reason: DeploymentAvailable + status: "True" + type: DeploymentAvailable + - lastTransitionTime: "2023-01-28T09:34:36Z" + message: Minimum replicas requirement is met + reason: DeploymentMinimumReplicasMet + status: "True" + type: DeploymentReplicasMinAvailable + - lastTransitionTime: "2023-01-28T09:44:36Z" + message: All replicas are available + reason: DeploymentReplicasAvailable + status: "True" + type: DeploymentReplicasAllAvailable + - lastTransitionTime: "2023-01-28T09:34:36Z" + message: The configured endpoint publishing strategy does not include a managed + load balancer + reason: EndpointPublishingStrategyExcludesManagedLoadBalancer + status: "False" + type: LoadBalancerManaged + - lastTransitionTime: "2023-01-28T09:34:36Z" + message: No DNS zones are defined in the cluster dns config. + reason: NoDNSZones + status: "False" + type: DNSManaged + - lastTransitionTime: "2023-01-28T09:34:36Z" + status: "True" + type: Available + - lastTransitionTime: "2023-01-28T09:34:36Z" + status: "False" + type: Progressing + - lastTransitionTime: "2023-01-28T09:34:36Z" + status: "False" + type: Degraded + - lastTransitionTime: "2023-01-28T09:34:36Z" + message: IngressController is upgradeable. + reason: Upgradeable + status: "True" + type: Upgradeable + domain: openshift-apps-shard-2.example.com + endpointPublishingStrategy: + hostNetwork: + httpPort: 80 + httpsPort: 443 + protocol: TCP + statsPort: 1936 + type: HostNetwork + observedGeneration: 5 + selector: ingresscontroller.operator.openshift.io/deployment-ingresscontroller=apps-shard-2 + tlsProfile: + ciphers: + - ECDHE-ECDSA-AES128-GCM-SHA256 + - ECDHE-RSA-AES128-GCM-SHA256 + - ECDHE-ECDSA-AES256-GCM-SHA384 + - ECDHE-RSA-AES256-GCM-SHA384 + - ECDHE-ECDSA-CHACHA20-POLY1305 + - ECDHE-RSA-CHACHA20-POLY1305 + - DHE-RSA-AES128-GCM-SHA256 + - DHE-RSA-AES256-GCM-SHA384 + - TLS_AES_128_GCM_SHA256 + - TLS_AES_256_GCM_SHA384 + - TLS_CHACHA20_POLY1305_SHA256 + minTLSVersion: VersionTLS12 diff --git a/resource_customizations/operator.openshift.io/IngressController/testdata/progressing_initialization.yaml b/resource_customizations/operator.openshift.io/IngressController/testdata/progressing_initialization.yaml new file mode 100644 index 0000000000000..470216e376e84 --- /dev/null +++ b/resource_customizations/operator.openshift.io/IngressController/testdata/progressing_initialization.yaml @@ -0,0 +1,36 @@ +--- +apiVersion: operator.openshift.io/v1 +kind: IngressController +metadata: + name: apps-shard-2 + namespace: openshift-ingress-operator +spec: + domain: openshift-apps-shard-2.example.com + endpointPublishingStrategy: + hostNetwork: + httpPort: 80 + httpsPort: 443 + statsPort: 1936 + type: HostNetwork + nodePlacement: + nodeSelector: + matchLabels: + node-role.kubernetes.io/worker: "" + replicas: 1 +status: + availableReplicas: 0 + conditions: + - lastTransitionTime: "2023-01-28T09:34:36Z" + reason: Valid + status: "True" + type: Admitted + domain: openshift-apps-shard-2.example.com + endpointPublishingStrategy: + hostNetwork: + httpPort: 80 + httpsPort: 443 + protocol: TCP + statsPort: 1936 + type: HostNetwork + observedGeneration: 1 + selector: "" diff --git a/resource_customizations/operator.openshift.io/IngressController/testdata/progressing_pod_rollout.yaml b/resource_customizations/operator.openshift.io/IngressController/testdata/progressing_pod_rollout.yaml new file mode 100644 index 0000000000000..73a33ae48613b --- /dev/null +++ b/resource_customizations/operator.openshift.io/IngressController/testdata/progressing_pod_rollout.yaml @@ -0,0 +1,101 @@ +--- +apiVersion: operator.openshift.io/v1 +kind: IngressController +metadata: + name: apps-shard-2 + namespace: openshift-ingress-operator +spec: + domain: openshift-apps-shard-2.example.com + endpointPublishingStrategy: + hostNetwork: + httpPort: 80 + httpsPort: 443 + statsPort: 1936 + type: HostNetwork + nodePlacement: + nodeSelector: + matchLabels: + node-role.kubernetes.io/worker: "" + replicas: 1 +status: + availableReplicas: 0 + conditions: + - lastTransitionTime: "2023-01-28T09:34:36Z" + reason: Valid + status: "True" + type: Admitted + - lastTransitionTime: "2023-01-28T09:34:36Z" + message: 'Some pods are not scheduled: Pod "router-apps-shard-2-7b5cb5f98d-gk4hj" + cannot be scheduled: 0/6 nodes are available: 2 node(s) didn''t have free ports + for the requested pod ports, 3 node(s) had untolerated taint {node-role.kubernetes.io/master: + }, 5 node(s) didn''t match Pod''s node affinity/selector. preemption: 0/6 nodes + are available: 1 node(s) didn''t have free ports for the requested pod ports, + 5 Preemption is not helpful for scheduling. Make sure you have sufficient worker + nodes.' + reason: PodsNotScheduled + status: "False" + type: PodsScheduled + - lastTransitionTime: "2023-01-28T09:34:36Z" + message: The deployment has Available status condition set to True + reason: DeploymentAvailable + status: "True" + type: DeploymentAvailable + - lastTransitionTime: "2023-01-28T09:34:36Z" + message: Minimum replicas requirement is met + reason: DeploymentMinimumReplicasMet + status: "True" + type: DeploymentReplicasMinAvailable + - lastTransitionTime: "2023-01-28T09:34:36Z" + message: 0/1 of replicas are available + reason: DeploymentReplicasNotAvailable + status: "False" + type: DeploymentReplicasAllAvailable + - lastTransitionTime: "2023-01-28T09:34:36Z" + message: The configured endpoint publishing strategy does not include a managed + load balancer + reason: EndpointPublishingStrategyExcludesManagedLoadBalancer + status: "False" + type: LoadBalancerManaged + - lastTransitionTime: "2023-01-28T09:34:36Z" + message: No DNS zones are defined in the cluster dns config. + reason: NoDNSZones + status: "False" + type: DNSManaged + - lastTransitionTime: "2023-01-28T09:34:36Z" + status: "True" + type: Available + - lastTransitionTime: "2023-01-28T09:34:36Z" + status: "False" + type: Progressing + - lastTransitionTime: "2023-01-28T09:34:36Z" + status: "False" + type: Degraded + - lastTransitionTime: "2023-01-28T09:34:36Z" + message: IngressController is upgradeable. + reason: Upgradeable + status: "True" + type: Upgradeable + domain: openshift-apps-shard-2.example.com + endpointPublishingStrategy: + hostNetwork: + httpPort: 80 + httpsPort: 443 + protocol: TCP + statsPort: 1936 + type: HostNetwork + observedGeneration: 2 + selector: ingresscontroller.operator.openshift.io/deployment-ingresscontroller=apps-shard-2 + tlsProfile: + ciphers: + - ECDHE-ECDSA-AES128-GCM-SHA256 + - ECDHE-RSA-AES128-GCM-SHA256 + - ECDHE-ECDSA-AES256-GCM-SHA384 + - ECDHE-RSA-AES256-GCM-SHA384 + - ECDHE-ECDSA-CHACHA20-POLY1305 + - ECDHE-RSA-CHACHA20-POLY1305 + - DHE-RSA-AES128-GCM-SHA256 + - DHE-RSA-AES256-GCM-SHA384 + - TLS_AES_128_GCM_SHA256 + - TLS_AES_256_GCM_SHA384 + - TLS_CHACHA20_POLY1305_SHA256 + minTLSVersion: VersionTLS12 diff --git a/resource_customizations/operators.coreos.com/Subscription/health.lua b/resource_customizations/operators.coreos.com/Subscription/health.lua index 41da0ee12bd5d..ca5f917f0715a 100644 --- a/resource_customizations/operators.coreos.com/Subscription/health.lua +++ b/resource_customizations/operators.coreos.com/Subscription/health.lua @@ -1,9 +1,9 @@ -health_status = {} +local health_status = {} if obj.status ~= nil then if obj.status.conditions ~= nil then - numDegraded = 0 - numPending = 0 - msg = "" + local numDegraded = 0 + local numPending = 0 + local msg = "" for i, condition in pairs(obj.status.conditions) do msg = msg .. i .. ": " .. condition.type .. " | " .. condition.status .. "\n" if condition.type == "InstallPlanPending" and condition.status == "True" then diff --git a/resource_customizations/pkg.crossplane.io/Provider/health.lua b/resource_customizations/pkg.crossplane.io/Provider/health.lua index 04242d67115a3..bcffa34e8cc36 100644 --- a/resource_customizations/pkg.crossplane.io/Provider/health.lua +++ b/resource_customizations/pkg.crossplane.io/Provider/health.lua @@ -1,8 +1,8 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then - installed = false - healthy = false + local installed = false + local healthy = false for i, condition in ipairs(obj.status.conditions) do if condition.type == "Installed" then installed = condition.status == "True" diff --git a/resource_customizations/platform.confluent.io/Connect/health.lua b/resource_customizations/platform.confluent.io/Connect/health.lua index 329585870952b..5ae4d7af34b73 100644 --- a/resource_customizations/platform.confluent.io/Connect/health.lua +++ b/resource_customizations/platform.confluent.io/Connect/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.phase ~= nil then if obj.status.phase == "RUNNING" then diff --git a/resource_customizations/platform.confluent.io/ControlCenter/health.lua b/resource_customizations/platform.confluent.io/ControlCenter/health.lua index 6b54872a2d0a0..2270545c7305b 100644 --- a/resource_customizations/platform.confluent.io/ControlCenter/health.lua +++ b/resource_customizations/platform.confluent.io/ControlCenter/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.phase ~= nil then if obj.status.phase == "RUNNING" then diff --git a/resource_customizations/platform.confluent.io/Kafka/health.lua b/resource_customizations/platform.confluent.io/Kafka/health.lua index 00033faf3132b..1abafd5d26a69 100644 --- a/resource_customizations/platform.confluent.io/Kafka/health.lua +++ b/resource_customizations/platform.confluent.io/Kafka/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.phase ~= nil then if obj.status.phase == "RUNNING" then diff --git a/resource_customizations/platform.confluent.io/KsqlDB/health.lua b/resource_customizations/platform.confluent.io/KsqlDB/health.lua index cfada56c772a5..263a72786a4e7 100644 --- a/resource_customizations/platform.confluent.io/KsqlDB/health.lua +++ b/resource_customizations/platform.confluent.io/KsqlDB/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.phase ~= nil then if obj.status.phase == "RUNNING" then diff --git a/resource_customizations/platform.confluent.io/SchemaRegistry/health.lua b/resource_customizations/platform.confluent.io/SchemaRegistry/health.lua index e5542ba826ed7..9aaa1a5ef3388 100644 --- a/resource_customizations/platform.confluent.io/SchemaRegistry/health.lua +++ b/resource_customizations/platform.confluent.io/SchemaRegistry/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.phase ~= nil then if obj.status.phase == "RUNNING" then diff --git a/resource_customizations/platform.confluent.io/Zookeeper/health.lua b/resource_customizations/platform.confluent.io/Zookeeper/health.lua index 20c0fa847fe5f..92f89b1fc6596 100644 --- a/resource_customizations/platform.confluent.io/Zookeeper/health.lua +++ b/resource_customizations/platform.confluent.io/Zookeeper/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.phase ~= nil then if obj.status.phase == "RUNNING" then diff --git a/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/health.lua b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/health.lua new file mode 100644 index 0000000000000..a83520eaa8265 --- /dev/null +++ b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/health.lua @@ -0,0 +1,29 @@ +local adopted = { status = "Unknown" } +local advertised = { status = "Unknown" } +local discovered = { status = "Unknown" } + +if obj.status ~= nil then + if obj.status.conditions ~= nil then + for i, c in ipairs(obj.status.conditions) do + if c.type == "Adopted" then + adopted = c + elseif c.type == "Advertised" then + advertised = c + elseif c.type == "Discoverable" then + discovered = c + end + end + end +end + +if adopted.status == "False" then + return { status = "Degraded", message = adopted.message } +elseif advertised.reason == "AdvertiseError" or advertised.reason == "UnadvertiseError" then + return { status = "Degraded", message = advertised.message } +elseif discovered.reason == "DiscoveryError" then + return { status = "Unknown", message = discovered.message } +elseif discovered.status == "True" then + return { status = "Healthy", message = discovered.message } +else + return { status = "Progressing", message = discovered.message } +end diff --git a/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/health_test.yaml b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/health_test.yaml new file mode 100644 index 0000000000000..1b9b30cf2e44b --- /dev/null +++ b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/health_test.yaml @@ -0,0 +1,29 @@ +tests: + - healthStatus: + status: Healthy + message: DNS-SD browse and lookup results match the advertised DNS records + inputPath: testdata/healthy.yaml + - healthStatus: + status: Progressing + message: DNS-SD browse could not find this instance + inputPath: testdata/progressing_negativeBrowse.yaml + - healthStatus: + status: Progressing + message: DNS-SD lookup could not find this instance + inputPath: testdata/progressing_negativeLookup.yaml + - healthStatus: + status: Degraded + message: none of the configured providers can advertise on "example.org" + inputPath: testdata/degraded_notAdopted.yaml + - healthStatus: + status: Degraded + message: "" + inputPath: testdata/degraded_advertiseError.yaml + - healthStatus: + status: Degraded + message: "" + inputPath: testdata/degraded_unadvertiseError.yaml + - healthStatus: + status: Unknown + message: "" + inputPath: testdata/unknown_discoveryError.yaml diff --git a/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/degraded_advertiseError.yaml b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/degraded_advertiseError.yaml new file mode 100644 index 0000000000000..905b2e9194e8b --- /dev/null +++ b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/degraded_advertiseError.yaml @@ -0,0 +1,35 @@ +apiVersion: proclaim.dogmatiq.io/v1 +kind: DNSSDServiceInstance +metadata: + creationTimestamp: "2023-03-20T01:47:37Z" + finalizers: + - proclaim.dogmatiq.io/unadvertise + generation: 2 + name: test-instance + namespace: proclaim + resourceVersion: "308914" + uid: 991a66a3-9b7e-4515-9a41-f7513e9b7b33 +spec: + instance: + attributes: + - baz: qux + flag: "" + foo: bar + - more: attrs + domain: example.org + name: test-instance + serviceType: _proclaim._tcp + targets: + - host: test.example.org + port: 8080 + priority: 0 + weight: 0 + ttl: 1m0s +status: + conditions: + - lastTransitionTime: "2023-03-20T01:47:40Z" + message: "" + observedGeneration: 2 + reason: AdvertiseError + status: "False" + type: Advertised diff --git a/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/degraded_notAdopted.yaml b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/degraded_notAdopted.yaml new file mode 100644 index 0000000000000..efccdb2c3f247 --- /dev/null +++ b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/degraded_notAdopted.yaml @@ -0,0 +1,35 @@ +apiVersion: proclaim.dogmatiq.io/v1 +kind: DNSSDServiceInstance +metadata: + creationTimestamp: "2023-03-20T01:47:37Z" + finalizers: + - proclaim.dogmatiq.io/unadvertise + generation: 2 + name: test-instance + namespace: proclaim + resourceVersion: "308914" + uid: 991a66a3-9b7e-4515-9a41-f7513e9b7b33 +spec: + instance: + attributes: + - baz: qux + flag: "" + foo: bar + - more: attrs + domain: example.org + name: test-instance + serviceType: _proclaim._tcp + targets: + - host: test.example.org + port: 8080 + priority: 0 + weight: 0 + ttl: 1m0s +status: + conditions: + - lastTransitionTime: "2023-03-20T01:47:40Z" + message: none of the configured providers can advertise on "example.org" + observedGeneration: 2 + reason: InstanceIgnored + status: "False" + type: Adopted diff --git a/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/degraded_unadvertiseError.yaml b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/degraded_unadvertiseError.yaml new file mode 100644 index 0000000000000..552eadbe702cc --- /dev/null +++ b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/degraded_unadvertiseError.yaml @@ -0,0 +1,35 @@ +apiVersion: proclaim.dogmatiq.io/v1 +kind: DNSSDServiceInstance +metadata: + creationTimestamp: "2023-03-20T01:47:37Z" + finalizers: + - proclaim.dogmatiq.io/unadvertise + generation: 2 + name: test-instance + namespace: proclaim + resourceVersion: "308914" + uid: 991a66a3-9b7e-4515-9a41-f7513e9b7b33 +spec: + instance: + attributes: + - baz: qux + flag: "" + foo: bar + - more: attrs + domain: example.org + name: test-instance + serviceType: _proclaim._tcp + targets: + - host: test.example.org + port: 8080 + priority: 0 + weight: 0 + ttl: 1m0s +status: + conditions: + - lastTransitionTime: "2023-03-20T01:47:40Z" + message: "" + observedGeneration: 2 + reason: UnadvertiseError + status: "False" + type: Advertised diff --git a/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/healthy.yaml b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/healthy.yaml new file mode 100644 index 0000000000000..f8ad890b9f934 --- /dev/null +++ b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/healthy.yaml @@ -0,0 +1,35 @@ +apiVersion: proclaim.dogmatiq.io/v1 +kind: DNSSDServiceInstance +metadata: + creationTimestamp: "2023-03-20T01:47:37Z" + finalizers: + - proclaim.dogmatiq.io/unadvertise + generation: 2 + name: test-instance + namespace: proclaim + resourceVersion: "308914" + uid: 991a66a3-9b7e-4515-9a41-f7513e9b7b33 +spec: + instance: + attributes: + - baz: qux + flag: "" + foo: bar + - more: attrs + domain: example.org + name: test-instance + serviceType: _proclaim._tcp + targets: + - host: test.example.org + port: 8080 + priority: 0 + weight: 0 + ttl: 1m0s +status: + conditions: + - lastTransitionTime: "2023-03-20T01:47:40Z" + message: DNS-SD browse and lookup results match the advertised DNS records + observedGeneration: 2 + reason: Discovered + status: "True" + type: Discoverable diff --git a/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/progressing_negativeBrowse.yaml b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/progressing_negativeBrowse.yaml new file mode 100644 index 0000000000000..e34e6c18f853a --- /dev/null +++ b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/progressing_negativeBrowse.yaml @@ -0,0 +1,35 @@ +apiVersion: proclaim.dogmatiq.io/v1 +kind: DNSSDServiceInstance +metadata: + creationTimestamp: "2023-03-20T01:47:37Z" + finalizers: + - proclaim.dogmatiq.io/unadvertise + generation: 2 + name: test-instance + namespace: proclaim + resourceVersion: "308914" + uid: 991a66a3-9b7e-4515-9a41-f7513e9b7b33 +spec: + instance: + attributes: + - baz: qux + flag: "" + foo: bar + - more: attrs + domain: example.org + name: test-instance + serviceType: _proclaim._tcp + targets: + - host: test.example.org + port: 8080 + priority: 0 + weight: 0 + ttl: 1m0s +status: + conditions: + - lastTransitionTime: "2023-03-20T01:47:40Z" + message: DNS-SD browse could not find this instance + observedGeneration: 2 + reason: NegativeBrowseResult + status: "False" + type: Discoverable diff --git a/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/progressing_negativeLookup.yaml b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/progressing_negativeLookup.yaml new file mode 100644 index 0000000000000..a563e7c9c40ca --- /dev/null +++ b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/progressing_negativeLookup.yaml @@ -0,0 +1,35 @@ +apiVersion: proclaim.dogmatiq.io/v1 +kind: DNSSDServiceInstance +metadata: + creationTimestamp: "2023-03-20T01:47:37Z" + finalizers: + - proclaim.dogmatiq.io/unadvertise + generation: 2 + name: test-instance + namespace: proclaim + resourceVersion: "308914" + uid: 991a66a3-9b7e-4515-9a41-f7513e9b7b33 +spec: + instance: + attributes: + - baz: qux + flag: "" + foo: bar + - more: attrs + domain: example.org + name: test-instance + serviceType: _proclaim._tcp + targets: + - host: test.example.org + port: 8080 + priority: 0 + weight: 0 + ttl: 1m0s +status: + conditions: + - lastTransitionTime: "2023-03-20T01:47:40Z" + message: DNS-SD lookup could not find this instance + observedGeneration: 2 + reason: NegativeLookupResult + status: "False" + type: Discoverable diff --git a/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/unknown_discoveryError.yaml b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/unknown_discoveryError.yaml new file mode 100644 index 0000000000000..c6139a504c3ff --- /dev/null +++ b/resource_customizations/proclaim.dogmatiq.io/DNSSDServiceInstance/testdata/unknown_discoveryError.yaml @@ -0,0 +1,35 @@ +apiVersion: proclaim.dogmatiq.io/v1 +kind: DNSSDServiceInstance +metadata: + creationTimestamp: "2023-03-20T01:47:37Z" + finalizers: + - proclaim.dogmatiq.io/unadvertise + generation: 2 + name: test-instance + namespace: proclaim + resourceVersion: "308914" + uid: 991a66a3-9b7e-4515-9a41-f7513e9b7b33 +spec: + instance: + attributes: + - baz: qux + flag: "" + foo: bar + - more: attrs + domain: example.org + name: test-instance + serviceType: _proclaim._tcp + targets: + - host: test.example.org + port: 8080 + priority: 0 + weight: 0 + ttl: 1m0s +status: + conditions: + - lastTransitionTime: "2023-03-20T01:47:40Z" + message: "" + observedGeneration: 2 + reason: DiscoveryError + status: "Unknown" + type: Discoverable diff --git a/resource_customizations/pubsub.cnrm.cloud.google.com/PubSubSubscription/health.lua b/resource_customizations/pubsub.cnrm.cloud.google.com/PubSubSubscription/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/pubsub.cnrm.cloud.google.com/PubSubSubscription/health.lua +++ b/resource_customizations/pubsub.cnrm.cloud.google.com/PubSubSubscription/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/pubsub.cnrm.cloud.google.com/PubSubTopic/health.lua b/resource_customizations/pubsub.cnrm.cloud.google.com/PubSubTopic/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/pubsub.cnrm.cloud.google.com/PubSubTopic/health.lua +++ b/resource_customizations/pubsub.cnrm.cloud.google.com/PubSubTopic/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/health.lua b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/health.lua new file mode 100644 index 0000000000000..d614828d461f2 --- /dev/null +++ b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/health.lua @@ -0,0 +1,38 @@ +local hs = {} +if obj.status ~= nil then + + if obj.status.state == "initializing" then + hs.status = "Progressing" + hs.message = obj.status.ready .. "/" .. obj.status.size .. " node(s) are ready" + return hs + end + + if obj.status.state == "ready" then + hs.status = "Healthy" + hs.message = obj.status.ready .. "/" .. obj.status.size .. " node(s) are ready" + return hs + end + + if obj.status.state == "paused" then + hs.status = "Unknown" + hs.message = "Cluster is paused" + return hs + end + + if obj.status.state == "stopping" then + hs.status = "Degraded" + hs.message = "Cluster is stopping (" .. obj.status.ready .. "/" .. obj.status.size .. " node(s) are ready)" + return hs + end + + if obj.status.state == "error" then + hs.status = "Degraded" + hs.message = "Cluster is on error: " .. table.concat(obj.status.message, ", ") + return hs + end + +end + +hs.status = "Unknown" +hs.message = "Cluster 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/pxc.percona.com/PerconaXtraDBCluster/health_test.yaml b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/health_test.yaml new file mode 100644 index 0000000000000..73b9968ff7a4c --- /dev/null +++ b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/health_test.yaml @@ -0,0 +1,25 @@ +tests: +- healthStatus: + status: Progressing + message: "0/1 node(s) are ready" + inputPath: testdata/initializing.yaml +- healthStatus: + status: Healthy + message: "1/1 node(s) are ready" + inputPath: testdata/ready.yaml +- healthStatus: + status: Unknown + message: "Cluster is paused" + inputPath: testdata/paused.yaml +- healthStatus: + status: Degraded + message: "Cluster is stopping (1/2 node(s) are ready)" + inputPath: testdata/stopping.yaml +- healthStatus: + status: Degraded + message: "Cluster is on error: we lost node" + inputPath: testdata/error.yaml +- healthStatus: + status: Unknown + message: "Cluster 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 diff --git a/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/error.yaml b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/error.yaml new file mode 100644 index 0000000000000..4a373358dcd8c --- /dev/null +++ b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/error.yaml @@ -0,0 +1,24 @@ +apiVersion: pxc.percona.com/v1 +kind: PerconaXtraDBCluster +metadata: + name: quickstart +spec: {} +status: + backup: {} + haproxy: {} + host: pxc-mysql-pxc + logcollector: {} + observedGeneration: 1 + pmm: {} + proxysql: {} + pxc: + image: "" + ready: 1 + size: 2 + status: error + version: 8.0.21-12.1 + ready: 1 + size: 2 + state: error + message: + - we lost node diff --git a/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/initializing.yaml b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/initializing.yaml new file mode 100644 index 0000000000000..11f3ff046543e --- /dev/null +++ b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/initializing.yaml @@ -0,0 +1,22 @@ +apiVersion: pxc.percona.com/v1 +kind: PerconaXtraDBCluster +metadata: + name: quickstart +spec: {} +status: + backup: {} + haproxy: {} + host: pxc-mysql-pxc + logcollector: {} + observedGeneration: 1 + pmm: {} + proxysql: {} + pxc: + image: '' + ready: 0 + size: 1 + status: initializing + version: 8.0.21-12.1 + ready: 0 + size: 1 + state: initializing diff --git a/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/paused.yaml b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/paused.yaml new file mode 100644 index 0000000000000..46440a23df7e2 --- /dev/null +++ b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/paused.yaml @@ -0,0 +1,22 @@ +apiVersion: pxc.percona.com/v1 +kind: PerconaXtraDBCluster +metadata: + name: quickstart +spec: {} +status: + backup: {} + haproxy: {} + host: pxc-mysql-pxc + logcollector: {} + observedGeneration: 1 + pmm: {} + proxysql: {} + pxc: + image: '' + ready: 1 + size: 1 + status: paused + version: 8.0.21-12.1 + ready: 1 + size: 1 + state: paused diff --git a/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/ready.yaml b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/ready.yaml new file mode 100644 index 0000000000000..bd7d82a2a08fe --- /dev/null +++ b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/ready.yaml @@ -0,0 +1,22 @@ +apiVersion: pxc.percona.com/v1 +kind: PerconaXtraDBCluster +metadata: + name: quickstart +spec: {} +status: + backup: {} + haproxy: {} + host: pxc-mysql-pxc + logcollector: {} + observedGeneration: 1 + pmm: {} + proxysql: {} + pxc: + image: '' + ready: 1 + size: 1 + status: ready + version: 8.0.21-12.1 + ready: 1 + size: 1 + state: ready diff --git a/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/stopping.yaml b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/stopping.yaml new file mode 100644 index 0000000000000..f527445c506a0 --- /dev/null +++ b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/stopping.yaml @@ -0,0 +1,22 @@ +apiVersion: pxc.percona.com/v1 +kind: PerconaXtraDBCluster +metadata: + name: quickstart +spec: {} +status: + backup: {} + haproxy: {} + host: pxc-mysql-pxc + logcollector: {} + observedGeneration: 1 + pmm: {} + proxysql: {} + pxc: + image: '' + ready: 1 + size: 2 + status: stopping + version: 8.0.21-12.1 + ready: 1 + size: 2 + state: stopping diff --git a/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/unknown.yaml b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/unknown.yaml new file mode 100644 index 0000000000000..c12b04682b18e --- /dev/null +++ b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/unknown.yaml @@ -0,0 +1,22 @@ +apiVersion: pxc.percona.com/v1 +kind: PerconaXtraDBCluster +metadata: + name: quickstart +spec: {} +status: + backup: {} + haproxy: {} + host: pxc-mysql-pxc + logcollector: {} + observedGeneration: 1 + pmm: {} + proxysql: {} + pxc: + image: '' + ready: 1 + size: 1 + status: dontknow + version: 8.0.21-12.1 + ready: 1 + size: 1 + state: dontknow diff --git a/resource_customizations/resourcemanager.cnrm.cloud.google.com/Project/health.lua b/resource_customizations/resourcemanager.cnrm.cloud.google.com/Project/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/resourcemanager.cnrm.cloud.google.com/Project/health.lua +++ b/resource_customizations/resourcemanager.cnrm.cloud.google.com/Project/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } 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/route.openshift.io/Route/health.lua b/resource_customizations/route.openshift.io/Route/health.lua index 9183d493bfad9..5a8400b2cee92 100644 --- a/resource_customizations/route.openshift.io/Route/health.lua +++ b/resource_customizations/route.openshift.io/Route/health.lua @@ -1,9 +1,9 @@ -health_status = {} +local health_status = {} if obj.status ~= nil then if obj.status.ingress ~= nil then - numIngressRules = 0 - numTrue = 0 - numFalse = 0 + local numIngressRules = 0 + local numTrue = 0 + local numFalse = 0 for _, ingressRules in pairs(obj.status.ingress) do numIngressRules = numIngressRules + 1 if obj.status.ingress ~= nil then 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/resource_customizations/serving.knative.dev/Service/health.lua b/resource_customizations/serving.knative.dev/Service/health.lua index 9867d8ab09df6..2a8c8a4683fd0 100644 --- a/resource_customizations/serving.knative.dev/Service/health.lua +++ b/resource_customizations/serving.knative.dev/Service/health.lua @@ -1,10 +1,10 @@ -health_status = {} +local health_status = {} health_status.status = "Progressing" health_status.message = "Waiting for status update." if obj.status ~= nil and obj.status.conditions ~= nil then - status_true = 0 - status_false = 0 - status_unknown = 0 + local status_true = 0 + local status_false = 0 + local status_unknown = 0 health_status.message = "" for i, condition in pairs(obj.status.conditions) do if condition.status == "True" and (condition.type == "ConfigurationsReady" or condition.type == "RoutesReady" or condition.type == "Ready") then diff --git a/resource_customizations/serving.kserve.io/InferenceService/health.lua b/resource_customizations/serving.kserve.io/InferenceService/health.lua new file mode 100644 index 0000000000000..fbcfbf77820f9 --- /dev/null +++ b/resource_customizations/serving.kserve.io/InferenceService/health.lua @@ -0,0 +1,40 @@ +local health_status = {} +health_status.status = "Progressing" +health_status.message = "Waiting for status update." +if obj.status ~= nil and obj.status.conditions ~= nil then + local status_true = 0 + local status_false = 0 + local status_unknown = 0 + health_status.message = "" + for i, condition in pairs(obj.status.conditions) do + if condition.status == "True" and (condition.type == "IngressReady" or condition.type == "PredictorConfigurationReady" or condition.type == "PredictorReady" or condition.type == "PredictorRouteReady" or condition.type == "Ready") then + status_true = status_true + 1 + elseif condition.status == "False" or condition.status == "Unknown" then + msg = condition.type .. " is " .. condition.status + if condition.reason ~= nil and condition.reason ~= "" then + msg = msg .. ", since " .. condition.reason .. "." + end + if condition.message ~= nil and condition.message ~= "" then + msg = msg .. " " .. condition.message + end + health_status.message = health_status.message .. msg .. "\n" + if condition.status == "False" then + status_false = status_false + 1 + else + status_unknown = status_unknown + 1 + end + end + end + if status_true == 5 and status_false == 0 and status_unknown == 0 then + health_status.message = "Inference Service is healthy." + health_status.status = "Healthy" + return health_status + elseif status_false > 0 then + health_status.status = "Degraded" + return health_status + else + health_status.status = "Progressing" + return health_status + end +end +return health_status \ No newline at end of file diff --git a/resource_customizations/serving.kserve.io/InferenceService/health_test.yaml b/resource_customizations/serving.kserve.io/InferenceService/health_test.yaml new file mode 100644 index 0000000000000..e8f32bd51f798 --- /dev/null +++ b/resource_customizations/serving.kserve.io/InferenceService/health_test.yaml @@ -0,0 +1,13 @@ +tests: +- healthStatus: + status: Progressing + message: "PredictorConfigurationReady is Unknown\nPredictorReady is Unknown, since RevisionMissing. Configuration \"hello-world-predictor-default\" is waiting for a Revision to become ready.\nPredictorRouteReady is Unknown, since RevisionMissing. Configuration \"hello-world-predictor-default\" is waiting for a Revision to become ready.\nReady is Unknown, since RevisionMissing. Configuration \"hello-world-predictor-default\" is waiting for a Revision to become ready.\n" + inputPath: testdata/progressing.yaml +- healthStatus: + status: Degraded + message: "IngressReady is False, since Predictor ingress not created.\nPredictorConfigurationReady is False, since RevisionFailed. Revision \"helloworld-00002\" failed with message: Container failed with: container exited with no error.\nPredictorReady is False, since RevisionFailed. Revision \"helloworld-00002\" failed with message: Container failed with: container exited with no error.\nReady is False, since Predictor ingress not created.\n" + inputPath: testdata/degraded.yaml +- healthStatus: + status: Healthy + message: Inference Service is healthy. + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/serving.kserve.io/InferenceService/testdata/degraded.yaml b/resource_customizations/serving.kserve.io/InferenceService/testdata/degraded.yaml new file mode 100644 index 0000000000000..0cd337860c670 --- /dev/null +++ b/resource_customizations/serving.kserve.io/InferenceService/testdata/degraded.yaml @@ -0,0 +1,30 @@ +apiVersion: serving.kserve.io/v1beta1 +kind: InferenceService +metadata: + name: helloworld + namespace: default +spec: {} +status: + conditions: + - lastTransitionTime: "2022-06-14T03:45:38Z" + reason: Predictor ingress not created + status: "False" + type: IngressReady + - lastTransitionTime: "2022-06-14T03:45:38Z" + message: 'Revision "helloworld-00002" failed with message: Container failed with: container exited with no error.' + reason: RevisionFailed + status: "False" + type: PredictorConfigurationReady + - lastTransitionTime: "2022-06-14T03:45:38Z" + message: 'Revision "helloworld-00002" failed with message: Container failed with: container exited with no error.' + reason: RevisionFailed + status: "False" + type: PredictorReady + - lastTransitionTime: "2022-06-14T03:45:38Z" + severity: Info + status: "True" + type: PredictorRouteReady + - lastTransitionTime: "2022-06-14T03:45:38Z" + reason: Predictor ingress not created + status: "False" + type: Ready diff --git a/resource_customizations/serving.kserve.io/InferenceService/testdata/healthy.yaml b/resource_customizations/serving.kserve.io/InferenceService/testdata/healthy.yaml new file mode 100644 index 0000000000000..3c28c61d48602 --- /dev/null +++ b/resource_customizations/serving.kserve.io/InferenceService/testdata/healthy.yaml @@ -0,0 +1,25 @@ +apiVersion: serving.kserve.io/v1beta1 +kind: InferenceService +metadata: + name: helloworld + namespace: default +spec: {} +status: + conditions: + - lastTransitionTime: "2023-06-20T22:44:51Z" + status: "True" + type: IngressReady + - lastTransitionTime: "2023-06-20T22:44:50Z" + severity: Info + status: "True" + type: PredictorConfigurationReady + - lastTransitionTime: "2023-06-20T22:44:51Z" + status: "True" + type: PredictorReady + - lastTransitionTime: "2023-06-20T22:44:51Z" + severity: Info + status: "True" + type: PredictorRouteReady + - lastTransitionTime: "2023-06-20T22:44:51Z" + status: "True" + type: Ready diff --git a/resource_customizations/serving.kserve.io/InferenceService/testdata/progressing.yaml b/resource_customizations/serving.kserve.io/InferenceService/testdata/progressing.yaml new file mode 100644 index 0000000000000..fab0a57b61f23 --- /dev/null +++ b/resource_customizations/serving.kserve.io/InferenceService/testdata/progressing.yaml @@ -0,0 +1,28 @@ +apiVersion: serving.kserve.io/v1beta1 +kind: InferenceService +metadata: + name: helloworld + namespace: default +spec: {} +status: + conditions: + - lastTransitionTime: "2023-06-21T22:25:58Z" + severity: Info + status: Unknown + type: PredictorConfigurationReady + - lastTransitionTime: "2023-06-21T22:25:58Z" + message: 'Configuration "hello-world-predictor-default" is waiting for a Revision to become ready.' + reason: RevisionMissing + status: Unknown + type: PredictorReady + - lastTransitionTime: "2023-06-21T22:25:58Z" + message: 'Configuration "hello-world-predictor-default" is waiting for a Revision to become ready.' + reason: RevisionMissing + severity: Info + status: Unknown + type: PredictorRouteReady + - lastTransitionTime: "2023-06-21T22:25:58Z" + message: 'Configuration "hello-world-predictor-default" is waiting for a Revision to become ready.' + reason: RevisionMissing + status: Unknown + type: Ready diff --git a/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/health.lua b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/health.lua new file mode 100644 index 0000000000000..082de2ca45761 --- /dev/null +++ b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/health.lua @@ -0,0 +1,18 @@ +local hs = {} + +if obj.status ~= nil and obj.status.readyToUse then + hs.status = "Healthy" + hs.message = "Ready to use" + return hs +end + +if obj.status ~= nil and obj.status.error ~= nil then + hs.status = "Degraded" + hs.message = obj.status.error.message + return hs +end + +hs.status = "Progressing" +hs.message = "Waiting for status" + +return hs diff --git a/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/health_test.yaml b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/health_test.yaml new file mode 100644 index 0000000000000..7914d4acdd3d8 --- /dev/null +++ b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/health_test.yaml @@ -0,0 +1,14 @@ +tests: +- healthStatus: + status: Progressing + message: "Waiting for status" + inputPath: testdata/initializing.yaml +- healthStatus: + status: Healthy + message: "Ready to use" + inputPath: testdata/good.yaml +- healthStatus: + status: Degraded + message: "VolumeSnapshotContent is dynamically provisioned while expecting a pre-provisioned one" + inputPath: testdata/bad.yaml + diff --git a/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/testdata/bad.yaml b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/testdata/bad.yaml new file mode 100644 index 0000000000000..2d7447f1334e7 --- /dev/null +++ b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/testdata/bad.yaml @@ -0,0 +1,14 @@ +apiVersion: snapshot.storage.k8s.io/v1 +kind: VolumeSnapshot +metadata: + name: data-04-06-2023 +spec: + source: + volumeSnapshotContentName: data-04-06-2023 +status: + error: + message: >- + VolumeSnapshotContent is dynamically provisioned while expecting a + pre-provisioned one + time: '2023-06-05T14:51:25Z' + readyToUse: false diff --git a/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/testdata/good.yaml b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/testdata/good.yaml new file mode 100644 index 0000000000000..b8a82eff5b45c --- /dev/null +++ b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/testdata/good.yaml @@ -0,0 +1,15 @@ +apiVersion: snapshot.storage.k8s.io/v1 +kind: VolumeSnapshot +metadata: + finalizers: + - snapshot.storage.kubernetes.io/volumesnapshot-as-source-protection + - snapshot.storage.kubernetes.io/volumesnapshot-bound-protection +status: + boundVolumeSnapshotContentName: snapcontent-7db10be0-424c-4ed2-9dfe-6c2120eae05b + creationTime: '2023-06-04T19:13:20Z' + readyToUse: true + restoreSize: 1Ti +spec: + source: + persistentVolumeClaimName: mask-data-process-trcxk-mysql-data + volumeSnapshotClassName: azure-tools diff --git a/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/testdata/initializing.yaml b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/testdata/initializing.yaml new file mode 100644 index 0000000000000..3df029d9a46cf --- /dev/null +++ b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshot/testdata/initializing.yaml @@ -0,0 +1,7 @@ +apiVersion: snapshot.storage.k8s.io/v1 +kind: VolumeSnapshot +metadata: + name: data-04-06-2023 +spec: + driver: disk.csi.azure.com +status: {} diff --git a/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/health.lua b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/health.lua new file mode 100644 index 0000000000000..082de2ca45761 --- /dev/null +++ b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/health.lua @@ -0,0 +1,18 @@ +local hs = {} + +if obj.status ~= nil and obj.status.readyToUse then + hs.status = "Healthy" + hs.message = "Ready to use" + return hs +end + +if obj.status ~= nil and obj.status.error ~= nil then + hs.status = "Degraded" + hs.message = obj.status.error.message + return hs +end + +hs.status = "Progressing" +hs.message = "Waiting for status" + +return hs diff --git a/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/health_test.yaml b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/health_test.yaml new file mode 100644 index 0000000000000..6cc455afabe0a --- /dev/null +++ b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/health_test.yaml @@ -0,0 +1,13 @@ +tests: +- healthStatus: + status: Progressing + message: "Waiting for status" + inputPath: testdata/initializing.yaml +- healthStatus: + status: Healthy + message: "Ready to use" + inputPath: testdata/good.yaml +- healthStatus: + status: Degraded + message: "Failed to check and update snapshot content" + inputPath: testdata/bad.yaml diff --git a/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/testdata/bad.yaml b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/testdata/bad.yaml new file mode 100644 index 0000000000000..d8d3d3d7b5ff0 --- /dev/null +++ b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/testdata/bad.yaml @@ -0,0 +1,12 @@ +apiVersion: snapshot.storage.k8s.io/v1 +kind: VolumeSnapshotContent +metadata: + name: data-04-06-2023 +spec: + driver: disk.csi.azure.com +status: + error: + message: >- + Failed to check and update snapshot content + time: '2023-06-05T15:44:50Z' + readyToUse: false diff --git a/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/testdata/good.yaml b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/testdata/good.yaml new file mode 100644 index 0000000000000..56166bec0c859 --- /dev/null +++ b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/testdata/good.yaml @@ -0,0 +1,20 @@ +apiVersion: snapshot.storage.k8s.io/v1 +kind: VolumeSnapshotContent +metadata: + creationTimestamp: '2023-06-04T19:13:19Z' + finalizers: + - snapshot.storage.kubernetes.io/volumesnapshotcontent-bound-protection +status: + creationTime: 1685906000388294100 + readyToUse: true + restoreSize: 1099511627776 + snapshotHandle: >- + /subscriptions/XXXXXX +spec: + driver: disk.csi.azure.com + source: + volumeHandle: >- + /subscriptions/XXXXXX + volumeSnapshotClassName: azure-tools + volumeSnapshotRef: + apiVersion: snapshot.storage.k8s.io/v1 diff --git a/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/testdata/initializing.yaml b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/testdata/initializing.yaml new file mode 100644 index 0000000000000..8558cf3e44966 --- /dev/null +++ b/resource_customizations/snapshot.storage.k8s.io/VolumeSnapshotContent/testdata/initializing.yaml @@ -0,0 +1,7 @@ +apiVersion: snapshot.storage.k8s.io/v1 +kind: VolumeSnapshotContent +metadata: + name: data-04-06-2023 +spec: + driver: disk.csi.azure.com +status: {} diff --git a/resource_customizations/sparkoperator.k8s.io/SparkApplication/health.lua b/resource_customizations/sparkoperator.k8s.io/SparkApplication/health.lua index 98e8feee227db..c900823186dae 100644 --- a/resource_customizations/sparkoperator.k8s.io/SparkApplication/health.lua +++ b/resource_customizations/sparkoperator.k8s.io/SparkApplication/health.lua @@ -1,4 +1,63 @@ -health_status = {} +local health_status = {} +-- Can't use standard lib, math.huge equivalent +local infinity = 2^1024-1 + +local function executor_range_api() + local min_executor_instances = 0 + local max_executor_instances = infinity + if obj.spec.dynamicAllocation.maxExecutors then + max_executor_instances = obj.spec.dynamicAllocation.maxExecutors + end + if obj.spec.dynamicAllocation.minExecutors then + min_executor_instances = obj.spec.dynamicAllocation.minExecutors + end + return min_executor_instances, max_executor_instances +end + +local function maybe_executor_range_spark_conf() + local min_executor_instances = 0 + local max_executor_instances = infinity + if obj.spec.sparkConf["spark.streaming.dynamicAllocation.enabled"] ~= nil and + obj.spec.sparkConf["spark.streaming.dynamicAllocation.enabled"] == "true" then + if(obj.spec.sparkConf["spark.streaming.dynamicAllocation.maxExecutors"] ~= nil) then + max_executor_instances = tonumber(obj.spec.sparkConf["spark.streaming.dynamicAllocation.maxExecutors"]) + end + if(obj.spec.sparkConf["spark.streaming.dynamicAllocation.minExecutors"] ~= nil) then + min_executor_instances = tonumber(obj.spec.sparkConf["spark.streaming.dynamicAllocation.minExecutors"]) + end + return min_executor_instances, max_executor_instances + elseif obj.spec.sparkConf["spark.dynamicAllocation.enabled"] ~= nil and + obj.spec.sparkConf["spark.dynamicAllocation.enabled"] == "true" then + if(obj.spec.sparkConf["spark.dynamicAllocation.maxExecutors"] ~= nil) then + max_executor_instances = tonumber(obj.spec.sparkConf["spark.dynamicAllocation.maxExecutors"]) + end + if(obj.spec.sparkConf["spark.dynamicAllocation.minExecutors"] ~= nil) then + min_executor_instances = tonumber(obj.spec.sparkConf["spark.dynamicAllocation.minExecutors"]) + end + return min_executor_instances, max_executor_instances + else + return nil + end +end + +local function maybe_executor_range() + if obj.spec["dynamicAllocation"] and obj.spec.dynamicAllocation.enabled then + return executor_range_api() + elseif obj.spec["sparkConf"] ~= nil then + return maybe_executor_range_spark_conf() + else + return nil + end +end + +local function dynamic_executors_without_spec_config() + if obj.spec.dynamicAllocation == nil and obj.spec.executor.instances == nil then + return true + else + return false + end +end + if obj.status ~= nil then if obj.status.applicationState.state ~= nil then if obj.status.applicationState.state == "" then @@ -9,13 +68,23 @@ if obj.status ~= nil then if obj.status.applicationState.state == "RUNNING" then if obj.status.executorState ~= nil then count=0 - executor_instances = obj.spec.executor.instances for i, executorState in pairs(obj.status.executorState) do if executorState == "RUNNING" then count=count+1 end end - if executor_instances == count then + if obj.spec.executor.instances ~= nil and obj.spec.executor.instances == count then + health_status.status = "Healthy" + health_status.message = "SparkApplication is Running" + return health_status + elseif maybe_executor_range() then + local min_executor_instances, max_executor_instances = maybe_executor_range() + if count >= min_executor_instances and count <= max_executor_instances then + health_status.status = "Healthy" + health_status.message = "SparkApplication is Running" + return health_status + end + elseif dynamic_executors_without_spec_config() and count >= 1 then health_status.status = "Healthy" health_status.message = "SparkApplication is Running" return health_status @@ -72,4 +141,4 @@ if obj.status ~= nil then end health_status.status = "Progressing" health_status.message = "Waiting for Executor pods" -return health_status \ No newline at end of file +return health_status diff --git a/resource_customizations/sparkoperator.k8s.io/SparkApplication/health_test.yaml b/resource_customizations/sparkoperator.k8s.io/SparkApplication/health_test.yaml index 7c971cbe666b8..e0ad7dfdf387d 100644 --- a/resource_customizations/sparkoperator.k8s.io/SparkApplication/health_test.yaml +++ b/resource_customizations/sparkoperator.k8s.io/SparkApplication/health_test.yaml @@ -11,3 +11,19 @@ tests: status: Healthy message: "SparkApplication is Running" inputPath: testdata/healthy.yaml +- healthStatus: + status: Healthy + message: "SparkApplication is Running" + inputPath: testdata/healthy_dynamic_alloc.yaml +- healthStatus: + status: Healthy + message: "SparkApplication is Running" + inputPath: testdata/healthy_dynamic_alloc_dstream.yaml +- healthStatus: + status: Healthy + message: "SparkApplication is Running" + inputPath: testdata/healthy_dynamic_alloc_operator_api.yaml +- healthStatus: + status: Healthy + message: "SparkApplication is Running" + inputPath: testdata/healthy_dynamic_alloc_without_spec_config.yaml diff --git a/resource_customizations/sparkoperator.k8s.io/SparkApplication/testdata/healthy_dynamic_alloc.yaml b/resource_customizations/sparkoperator.k8s.io/SparkApplication/testdata/healthy_dynamic_alloc.yaml new file mode 100644 index 0000000000000..9ff52e78b98c5 --- /dev/null +++ b/resource_customizations/sparkoperator.k8s.io/SparkApplication/testdata/healthy_dynamic_alloc.yaml @@ -0,0 +1,37 @@ +apiVersion: sparkoperator.k8s.io/v1beta2 +kind: SparkApplication +metadata: + generation: 4 + labels: + argocd.argoproj.io/instance: spark-job + name: spark-job-app + namespace: spark-cluster + resourceVersion: "31812990" + uid: bfee52b0-74ca-4465-8005-f6643097ed64 +spec: + executor: + instances: 4 + sparkConf: + spark.dynamicAllocation.enabled: 'true' + spark.dynamicAllocation.maxExecutors: '10' + spark.dynamicAllocation.minExecutors: '2' +status: + applicationState: + state: RUNNING + driverInfo: + podName: ingestion-datalake-news-app-driver + webUIAddress: 172.20.207.161:4040 + webUIPort: 4040 + webUIServiceName: ingestion-datalake-news-app-ui-svc + executionAttempts: 13 + executorState: + ingestion-datalake-news-app-1591613851251-exec-1: RUNNING + ingestion-datalake-news-app-1591613851251-exec-2: RUNNING + ingestion-datalake-news-app-1591613851251-exec-4: RUNNING + ingestion-datalake-news-app-1591613851251-exec-5: RUNNING + ingestion-datalake-news-app-1591613851251-exec-6: RUNNING + lastSubmissionAttemptTime: "2020-06-08T10:57:32Z" + sparkApplicationId: spark-a5920b2a5aa04d22a737c60759b5bf82 + submissionAttempts: 1 + submissionID: 3e713ec8-9f6c-4e78-ac28-749797c846f0 + terminationTime: null diff --git a/resource_customizations/sparkoperator.k8s.io/SparkApplication/testdata/healthy_dynamic_alloc_dstream.yaml b/resource_customizations/sparkoperator.k8s.io/SparkApplication/testdata/healthy_dynamic_alloc_dstream.yaml new file mode 100644 index 0000000000000..ce24ff77177d2 --- /dev/null +++ b/resource_customizations/sparkoperator.k8s.io/SparkApplication/testdata/healthy_dynamic_alloc_dstream.yaml @@ -0,0 +1,35 @@ +apiVersion: sparkoperator.k8s.io/v1beta2 +kind: SparkApplication +metadata: + generation: 4 + labels: + argocd.argoproj.io/instance: spark-job + name: spark-job-app + namespace: spark-cluster + resourceVersion: "31812990" + uid: bfee52b0-74ca-4465-8005-f6643097ed64 +spec: + executor: + instances: 4 + sparkConf: + spark.streaming.dynamicAllocation.enabled: 'true' + spark.streaming.dynamicAllocation.maxExecutors: '10' + spark.streaming.dynamicAllocation.minExecutors: '2' +status: + applicationState: + state: RUNNING + driverInfo: + podName: ingestion-datalake-news-app-driver + webUIAddress: 172.20.207.161:4040 + webUIPort: 4040 + webUIServiceName: ingestion-datalake-news-app-ui-svc + executionAttempts: 13 + executorState: + ingestion-datalake-news-app-1591613851251-exec-1: RUNNING + ingestion-datalake-news-app-1591613851251-exec-4: RUNNING + ingestion-datalake-news-app-1591613851251-exec-6: RUNNING + lastSubmissionAttemptTime: "2020-06-08T10:57:32Z" + sparkApplicationId: spark-a5920b2a5aa04d22a737c60759b5bf82 + submissionAttempts: 1 + submissionID: 3e713ec8-9f6c-4e78-ac28-749797c846f0 + terminationTime: null diff --git a/resource_customizations/sparkoperator.k8s.io/SparkApplication/testdata/healthy_dynamic_alloc_operator_api.yaml b/resource_customizations/sparkoperator.k8s.io/SparkApplication/testdata/healthy_dynamic_alloc_operator_api.yaml new file mode 100644 index 0000000000000..538a27991bb5a --- /dev/null +++ b/resource_customizations/sparkoperator.k8s.io/SparkApplication/testdata/healthy_dynamic_alloc_operator_api.yaml @@ -0,0 +1,38 @@ +apiVersion: sparkoperator.k8s.io/v1beta2 +kind: SparkApplication +metadata: + generation: 4 + labels: + argocd.argoproj.io/instance: spark-job + name: spark-job-app + namespace: spark-cluster + resourceVersion: "31812990" + uid: bfee52b0-74ca-4465-8005-f6643097ed64 +spec: + executor: + instances: 4 + dynamicAllocation: + enabled: true + initialExecutors: 2 + minExecutors: 2 + maxExecutors: 10 +status: + applicationState: + state: RUNNING + driverInfo: + podName: ingestion-datalake-news-app-driver + webUIAddress: 172.20.207.161:4040 + webUIPort: 4040 + webUIServiceName: ingestion-datalake-news-app-ui-svc + executionAttempts: 13 + executorState: + ingestion-datalake-news-app-1591613851251-exec-1: RUNNING + ingestion-datalake-news-app-1591613851251-exec-2: RUNNING + ingestion-datalake-news-app-1591613851251-exec-4: RUNNING + ingestion-datalake-news-app-1591613851251-exec-5: RUNNING + ingestion-datalake-news-app-1591613851251-exec-6: RUNNING + lastSubmissionAttemptTime: "2020-06-08T10:57:32Z" + sparkApplicationId: spark-a5920b2a5aa04d22a737c60759b5bf82 + submissionAttempts: 1 + submissionID: 3e713ec8-9f6c-4e78-ac28-749797c846f0 + terminationTime: null diff --git a/resource_customizations/sparkoperator.k8s.io/SparkApplication/testdata/healthy_dynamic_alloc_without_spec_config.yaml b/resource_customizations/sparkoperator.k8s.io/SparkApplication/testdata/healthy_dynamic_alloc_without_spec_config.yaml new file mode 100644 index 0000000000000..a2ab7b85b5c50 --- /dev/null +++ b/resource_customizations/sparkoperator.k8s.io/SparkApplication/testdata/healthy_dynamic_alloc_without_spec_config.yaml @@ -0,0 +1,31 @@ +apiVersion: sparkoperator.k8s.io/v1beta2 +kind: SparkApplication +metadata: + generation: 4 + labels: + argocd.argoproj.io/instance: spark-job + name: spark-job-app + namespace: spark-cluster + resourceVersion: "31812990" + uid: bfee52b0-74ca-4465-8005-f6643097ed64 +spec: + executor: {} +status: + applicationState: + state: RUNNING + driverInfo: + podName: ingestion-datalake-news-app-driver + webUIAddress: 172.20.207.161:4040 + webUIPort: 4040 + webUIServiceName: ingestion-datalake-news-app-ui-svc + executionAttempts: 13 + executorState: + ingestion-datalake-news-app-1591613851251-exec-1: RUNNING + ingestion-datalake-news-app-1591613851251-exec-2: RUNNING + ingestion-datalake-news-app-1591613851251-exec-4: RUNNING + ingestion-datalake-news-app-1591613851251-exec-5: RUNNING + lastSubmissionAttemptTime: "2020-06-08T10:57:32Z" + sparkApplicationId: spark-a5920b2a5aa04d22a737c60759b5bf82 + submissionAttempts: 1 + submissionID: 3e713ec8-9f6c-4e78-ac28-749797c846f0 + terminationTime: null diff --git a/resource_customizations/spot.io/SpotDeployment/health.lua b/resource_customizations/spot.io/SpotDeployment/health.lua index 030e2c5493ba8..cd39bcaa1325e 100644 --- a/resource_customizations/spot.io/SpotDeployment/health.lua +++ b/resource_customizations/spot.io/SpotDeployment/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status == nil or obj.status.conditions == nil then return hs diff --git a/resource_customizations/sql.cnrm.cloud.google.com/SQLDatabase/health.lua b/resource_customizations/sql.cnrm.cloud.google.com/SQLDatabase/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/sql.cnrm.cloud.google.com/SQLDatabase/health.lua +++ b/resource_customizations/sql.cnrm.cloud.google.com/SQLDatabase/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/sql.cnrm.cloud.google.com/SQLInstance/health.lua b/resource_customizations/sql.cnrm.cloud.google.com/SQLInstance/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/sql.cnrm.cloud.google.com/SQLInstance/health.lua +++ b/resource_customizations/sql.cnrm.cloud.google.com/SQLInstance/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/stacks.crossplane.io/ClusterStackInstall/health.lua b/resource_customizations/stacks.crossplane.io/ClusterStackInstall/health.lua index 9a213cd956a9f..9e94c5fb80660 100644 --- a/resource_customizations/stacks.crossplane.io/ClusterStackInstall/health.lua +++ b/resource_customizations/stacks.crossplane.io/ClusterStackInstall/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Waiting for stack to be installed" } diff --git a/resource_customizations/storage.cnrm.cloud.google.com/StorageBucket/health.lua b/resource_customizations/storage.cnrm.cloud.google.com/StorageBucket/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/storage.cnrm.cloud.google.com/StorageBucket/health.lua +++ b/resource_customizations/storage.cnrm.cloud.google.com/StorageBucket/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/storage.cnrm.cloud.google.com/StorageBucketAccessControl/health.lua b/resource_customizations/storage.cnrm.cloud.google.com/StorageBucketAccessControl/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/storage.cnrm.cloud.google.com/StorageBucketAccessControl/health.lua +++ b/resource_customizations/storage.cnrm.cloud.google.com/StorageBucketAccessControl/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/storage.cnrm.cloud.google.com/StorageDefaultObjectAccessControl/health.lua b/resource_customizations/storage.cnrm.cloud.google.com/StorageDefaultObjectAccessControl/health.lua index 63ce5d12a4fbf..585b5e27a3e98 100644 --- a/resource_customizations/storage.cnrm.cloud.google.com/StorageDefaultObjectAccessControl/health.lua +++ b/resource_customizations/storage.cnrm.cloud.google.com/StorageDefaultObjectAccessControl/health.lua @@ -1,4 +1,4 @@ -hs = { +local hs = { status = "Progressing", message = "Update in progress" } diff --git a/resource_customizations/tower.ansible.com/AnsibleJob/health.lua b/resource_customizations/tower.ansible.com/AnsibleJob/health.lua new file mode 100644 index 0000000000000..1e4a514c500e1 --- /dev/null +++ b/resource_customizations/tower.ansible.com/AnsibleJob/health.lua @@ -0,0 +1,25 @@ +hs = {} +if obj.status ~= nil then + if obj.status.ansibleJobResult ~= nil then + jobstatus = obj.status.ansibleJobResult.status + if jobstatus == "successful" then + hs.status = "Healthy" + hs.message = jobstatus .. " job - " .. obj.status.ansibleJobResult.url + return hs + end + if jobstatus == "failed" or jobstatus == "error" or jobstatus == "canceled" then + hs.status = "Degraded" + hs.message = jobstatus .. " job - " .. obj.status.ansibleJobResult.url + return hs + end + if jobstatus == "new" or jobstatus == "pending" or jobstatus == "waiting" or jobstatus == "running" then + hs.status = "Progressing" + hs.message = jobstatus .. " job - " .. obj.status.ansibleJobResult.url + return hs + end + end +end + +hs.status = "Progressing" +hs.message = "Waiting for AnsibleJob" +return hs diff --git a/resource_customizations/tower.ansible.com/AnsibleJob/health_test.yaml b/resource_customizations/tower.ansible.com/AnsibleJob/health_test.yaml new file mode 100644 index 0000000000000..bb4143ae5f5a3 --- /dev/null +++ b/resource_customizations/tower.ansible.com/AnsibleJob/health_test.yaml @@ -0,0 +1,37 @@ +tests: +- healthStatus: + status: Progressing + message: Waiting for AnsibleJob + inputPath: testdata/progressing_noStatus.yaml +- healthStatus: + status: Progressing + message: 'new job - https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1' + inputPath: testdata/progressing_new.yaml +- healthStatus: + status: Progressing + message: 'pending job - https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1' + inputPath: testdata/progressing_pending.yaml +- healthStatus: + status: Progressing + message: 'running job - https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1' + inputPath: testdata/progressing_running.yaml +- healthStatus: + status: Progressing + message: 'waiting job - https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1' + inputPath: testdata/progressing_waiting.yaml +- healthStatus: + status: Degraded + message: 'canceled job - https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1' + inputPath: testdata/degraded_canceled.yaml +- healthStatus: + status: Degraded + message: 'error job - https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1' + inputPath: testdata/degraded_error.yaml +- healthStatus: + status: Degraded + message: 'failed job - https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1' + inputPath: testdata/degraded_failed.yaml +- healthStatus: + status: Healthy + message: 'successful job - https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1' + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/tower.ansible.com/AnsibleJob/testdata/degraded_canceled.yaml b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/degraded_canceled.yaml new file mode 100644 index 0000000000000..55fa0cdec7767 --- /dev/null +++ b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/degraded_canceled.yaml @@ -0,0 +1,27 @@ +apiVersion: tower.ansible.com/v1alpha1 +kind: AnsibleJob +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + creationTimestamp: "2023-06-27T20:22:22Z" + generateName: prehook-test- + generation: 1 + labels: + app.kubernetes.io/instance: ansible-hooks + tower_job_id: "1" + name: prehook-test-dfcff01-presync-1687897341 + namespace: argocd + resourceVersion: "6536518" + uid: 09fa0d39-a170-4c37-a3b0-6e140e029868 +spec: + job_template_name: Demo Job Template + tower_auth_secret: toweraccess +status: + ansibleJobResult: + changed: true + elapsed: "5.21" + failed: false + finished: "2023-06-27T20:22:40.116381Z" + started: "2023-06-27T20:22:34.906399Z" + status: canceled + url: https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1 diff --git a/resource_customizations/tower.ansible.com/AnsibleJob/testdata/degraded_error.yaml b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/degraded_error.yaml new file mode 100644 index 0000000000000..0ebb059ea8e2f --- /dev/null +++ b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/degraded_error.yaml @@ -0,0 +1,27 @@ +apiVersion: tower.ansible.com/v1alpha1 +kind: AnsibleJob +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + creationTimestamp: "2023-06-27T20:22:22Z" + generateName: prehook-test- + generation: 1 + labels: + app.kubernetes.io/instance: ansible-hooks + tower_job_id: "1" + name: prehook-test-dfcff01-presync-1687897341 + namespace: argocd + resourceVersion: "6536518" + uid: 09fa0d39-a170-4c37-a3b0-6e140e029868 +spec: + job_template_name: Demo Job Template + tower_auth_secret: toweraccess +status: + ansibleJobResult: + changed: true + elapsed: "5.21" + failed: true + finished: "2023-06-27T20:22:40.116381Z" + started: "2023-06-27T20:22:34.906399Z" + status: error + url: https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1 diff --git a/resource_customizations/tower.ansible.com/AnsibleJob/testdata/degraded_failed.yaml b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/degraded_failed.yaml new file mode 100644 index 0000000000000..0400570b15f7f --- /dev/null +++ b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/degraded_failed.yaml @@ -0,0 +1,27 @@ +apiVersion: tower.ansible.com/v1alpha1 +kind: AnsibleJob +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + creationTimestamp: "2023-06-27T20:22:22Z" + generateName: prehook-test- + generation: 1 + labels: + app.kubernetes.io/instance: ansible-hooks + tower_job_id: "1" + name: prehook-test-dfcff01-presync-1687897341 + namespace: argocd + resourceVersion: "6536518" + uid: 09fa0d39-a170-4c37-a3b0-6e140e029868 +spec: + job_template_name: Demo Job Template + tower_auth_secret: toweraccess +status: + ansibleJobResult: + changed: true + elapsed: "5.21" + failed: true + finished: "2023-06-27T20:22:40.116381Z" + started: "2023-06-27T20:22:34.906399Z" + status: failed + url: https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1 diff --git a/resource_customizations/tower.ansible.com/AnsibleJob/testdata/healthy.yaml b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/healthy.yaml new file mode 100644 index 0000000000000..395a1bd09625f --- /dev/null +++ b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/healthy.yaml @@ -0,0 +1,27 @@ +apiVersion: tower.ansible.com/v1alpha1 +kind: AnsibleJob +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + creationTimestamp: "2023-06-27T20:22:22Z" + generateName: prehook-test- + generation: 1 + labels: + app.kubernetes.io/instance: ansible-hooks + tower_job_id: "1" + name: prehook-test-dfcff01-presync-1687897341 + namespace: argocd + resourceVersion: "6536518" + uid: 09fa0d39-a170-4c37-a3b0-6e140e029868 +spec: + job_template_name: Demo Job Template + tower_auth_secret: toweraccess +status: + ansibleJobResult: + changed: true + elapsed: "5.21" + failed: false + finished: "2023-06-27T20:22:40.116381Z" + started: "2023-06-27T20:22:34.906399Z" + status: successful + url: https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1 diff --git a/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_new.yaml b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_new.yaml new file mode 100644 index 0000000000000..2e700d3708c58 --- /dev/null +++ b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_new.yaml @@ -0,0 +1,25 @@ +apiVersion: tower.ansible.com/v1alpha1 +kind: AnsibleJob +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + creationTimestamp: "2023-06-27T20:22:22Z" + generateName: prehook-test- + generation: 1 + labels: + app.kubernetes.io/instance: ansible-hooks + tower_job_id: "1" + name: prehook-test-dfcff01-presync-1687897341 + namespace: argocd + resourceVersion: "6536518" + uid: 09fa0d39-a170-4c37-a3b0-6e140e029868 +spec: + job_template_name: Demo Job Template + tower_auth_secret: toweraccess +status: + ansibleJobResult: + changed: true + failed: false + started: "2023-06-27T20:22:34.906399Z" + status: new + url: https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1 diff --git a/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_noStatus.yaml b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_noStatus.yaml new file mode 100644 index 0000000000000..a6e1701bf3268 --- /dev/null +++ b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_noStatus.yaml @@ -0,0 +1,17 @@ +apiVersion: tower.ansible.com/v1alpha1 +kind: AnsibleJob +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + creationTimestamp: "2023-06-27T20:22:22Z" + generateName: prehook-test- + generation: 1 + labels: + app.kubernetes.io/instance: ansible-hooks + name: prehook-test-dfcff01-presync-1687897341 + namespace: argocd + resourceVersion: "6536518" + uid: 09fa0d39-a170-4c37-a3b0-6e140e029868 +spec: + job_template_name: Demo Job Template + tower_auth_secret: toweraccess diff --git a/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_pending.yaml b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_pending.yaml new file mode 100644 index 0000000000000..ffabaf4ee64e6 --- /dev/null +++ b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_pending.yaml @@ -0,0 +1,25 @@ +apiVersion: tower.ansible.com/v1alpha1 +kind: AnsibleJob +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + creationTimestamp: "2023-06-27T20:22:22Z" + generateName: prehook-test- + generation: 1 + labels: + app.kubernetes.io/instance: ansible-hooks + tower_job_id: "1" + name: prehook-test-dfcff01-presync-1687897341 + namespace: argocd + resourceVersion: "6536518" + uid: 09fa0d39-a170-4c37-a3b0-6e140e029868 +spec: + job_template_name: Demo Job Template + tower_auth_secret: toweraccess +status: + ansibleJobResult: + changed: true + failed: false + started: "2023-06-27T20:22:34.906399Z" + status: pending + url: https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1 diff --git a/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_running.yaml b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_running.yaml new file mode 100644 index 0000000000000..6e369f0aaecea --- /dev/null +++ b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_running.yaml @@ -0,0 +1,25 @@ +apiVersion: tower.ansible.com/v1alpha1 +kind: AnsibleJob +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + creationTimestamp: "2023-06-27T20:22:22Z" + generateName: prehook-test- + generation: 1 + labels: + app.kubernetes.io/instance: ansible-hooks + tower_job_id: "1" + name: prehook-test-dfcff01-presync-1687897341 + namespace: argocd + resourceVersion: "6536518" + uid: 09fa0d39-a170-4c37-a3b0-6e140e029868 +spec: + job_template_name: Demo Job Template + tower_auth_secret: toweraccess +status: + ansibleJobResult: + changed: true + failed: false + started: "2023-06-27T20:22:34.906399Z" + status: running + url: https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1 diff --git a/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_waiting.yaml b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_waiting.yaml new file mode 100644 index 0000000000000..c6f192cca70b0 --- /dev/null +++ b/resource_customizations/tower.ansible.com/AnsibleJob/testdata/progressing_waiting.yaml @@ -0,0 +1,25 @@ +apiVersion: tower.ansible.com/v1alpha1 +kind: AnsibleJob +metadata: + annotations: + argocd.argoproj.io/hook: PreSync + creationTimestamp: "2023-06-27T20:22:22Z" + generateName: prehook-test- + generation: 1 + labels: + app.kubernetes.io/instance: ansible-hooks + tower_job_id: "1" + name: prehook-test-dfcff01-presync-1687897341 + namespace: argocd + resourceVersion: "6536518" + uid: 09fa0d39-a170-4c37-a3b0-6e140e029868 +spec: + job_template_name: Demo Job Template + tower_auth_secret: toweraccess +status: + ansibleJobResult: + changed: true + failed: false + started: "2023-06-27T20:22:34.906399Z" + status: waiting + url: https://argocd.test.ansiblejob.custom.health.com/#/jobs/playbook/1 diff --git a/resource_customizations/trident.netapp.io/TridentBackendConfig/health.lua b/resource_customizations/trident.netapp.io/TridentBackendConfig/health.lua index 8f8b0ca9c5d83..614915a4edc00 100644 --- a/resource_customizations/trident.netapp.io/TridentBackendConfig/health.lua +++ b/resource_customizations/trident.netapp.io/TridentBackendConfig/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.phase == "Bound" and obj.status.lastOperationStatus == "Success" then hs.status = "Healthy" diff --git a/resource_customizations/trident.netapp.io/TridentOrchestrator/health.lua b/resource_customizations/trident.netapp.io/TridentOrchestrator/health.lua index 4ceecef2f0ec0..18c3b89fab0de 100644 --- a/resource_customizations/trident.netapp.io/TridentOrchestrator/health.lua +++ b/resource_customizations/trident.netapp.io/TridentOrchestrator/health.lua @@ -1,4 +1,4 @@ -hs = {} +local hs = {} if obj.status ~= nil then if obj.status.status == "Installed" then hs.status = "Healthy" diff --git a/resource_customizations/work.karmada.io/ClusterResourceBinding/health.lua b/resource_customizations/work.karmada.io/ClusterResourceBinding/health.lua index 5098ae9fe2e56..5e94523c1f043 100644 --- a/resource_customizations/work.karmada.io/ClusterResourceBinding/health.lua +++ b/resource_customizations/work.karmada.io/ClusterResourceBinding/health.lua @@ -1,4 +1,4 @@ -health_status = {} +local health_status = {} if obj.status == nil then health_status.status = "Progressing" health_status.message = "Current resource status is insufficient" diff --git a/resource_customizations/work.karmada.io/ResourceBinding/health.lua b/resource_customizations/work.karmada.io/ResourceBinding/health.lua index 5098ae9fe2e56..5e94523c1f043 100644 --- a/resource_customizations/work.karmada.io/ResourceBinding/health.lua +++ b/resource_customizations/work.karmada.io/ResourceBinding/health.lua @@ -1,4 +1,4 @@ -health_status = {} +local health_status = {} if obj.status == nil then health_status.status = "Progressing" health_status.message = "Current resource status is insufficient" diff --git a/resource_customizations/zookeeper.pravega.io/ZookeeperCluster/health.lua b/resource_customizations/zookeeper.pravega.io/ZookeeperCluster/health.lua index 5228f53fb682c..9e597ae097f27 100644 --- a/resource_customizations/zookeeper.pravega.io/ZookeeperCluster/health.lua +++ b/resource_customizations/zookeeper.pravega.io/ZookeeperCluster/health.lua @@ -1,4 +1,4 @@ -health_status = {} +local health_status = {} if obj.status ~= nil then if obj.status.readyReplicas ~= 0 and obj.status.readyReplicas == obj.status.replicas then health_status.status = "Healthy" diff --git a/server/application/application.go b/server/application/application.go index dbdce9cafce2e..ec0db45a11f22 100644 --- a/server/application/application.go +++ b/server/application/application.go @@ -28,6 +28,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" @@ -46,10 +47,10 @@ import ( "github.com/argoproj/argo-cd/v2/server/rbacpolicy" "github.com/argoproj/argo-cd/v2/util/argo" argoutil "github.com/argoproj/argo-cd/v2/util/argo" + "github.com/argoproj/argo-cd/v2/util/collections" "github.com/argoproj/argo-cd/v2/util/db" "github.com/argoproj/argo-cd/v2/util/env" "github.com/argoproj/argo-cd/v2/util/git" - "github.com/argoproj/argo-cd/v2/util/glob" ioutil "github.com/argoproj/argo-cd/v2/util/io" "github.com/argoproj/argo-cd/v2/util/lua" "github.com/argoproj/argo-cd/v2/util/manifeststream" @@ -57,6 +58,8 @@ import ( "github.com/argoproj/argo-cd/v2/util/security" "github.com/argoproj/argo-cd/v2/util/session" "github.com/argoproj/argo-cd/v2/util/settings" + + applicationType "github.com/argoproj/argo-cd/v2/pkg/apis/application" ) type AppResourceTreeFn func(ctx context.Context, app *appv1.Application) (*appv1.ApplicationTree, error) @@ -68,7 +71,8 @@ const ( ) var ( - watchAPIBufferSize = env.ParseNumFromEnv(argocommon.EnvWatchAPIBufferSize, 1000, 0, math.MaxInt32) + watchAPIBufferSize = env.ParseNumFromEnv(argocommon.EnvWatchAPIBufferSize, 1000, 0, math.MaxInt32) + permissionDeniedErr = status.Error(codes.PermissionDenied, "permission denied") ) // Server provides an Application service @@ -78,7 +82,7 @@ type Server struct { appclientset appclientset.Interface appLister applisters.ApplicationLister appInformer cache.SharedIndexInformer - appBroadcaster *broadcasterHandler + appBroadcaster Broadcaster repoClientset apiclient.Clientset kubectl kube.Kubectl db db.ArgoDB @@ -98,6 +102,7 @@ func NewServer( appclientset appclientset.Interface, appLister applisters.ApplicationLister, appInformer cache.SharedIndexInformer, + appBroadcaster Broadcaster, repoClientset apiclient.Clientset, cache *servercache.Cache, kubectl kube.Kubectl, @@ -108,8 +113,13 @@ func NewServer( projInformer cache.SharedIndexInformer, enabledNamespaces []string, ) (application.ApplicationServiceServer, AppResourceTreeFn) { - appBroadcaster := &broadcasterHandler{} - appInformer.AddEventHandler(appBroadcaster) + if appBroadcaster == nil { + appBroadcaster = &broadcasterHandler{} + } + _, err := appInformer.AddEventHandler(appBroadcaster) + if err != nil { + log.Error(err) + } s := &Server{ ns: namespace, appclientset: appclientset, @@ -131,6 +141,115 @@ func NewServer( return s, s.getAppResources } +// getAppEnforceRBAC gets the Application with the given name in the given namespace. If no namespace is +// specified, the Application is fetched from the default namespace (the one in which the API server is running). +// +// If the user does not provide a "project," then we have to be very careful how we respond. If an app with the given +// name exists, and the user has access to that app in the app's project, we return the app. If the app exists but the +// user does not have access, we return "permission denied." If the app does not exist, we return "permission denied" - +// if we responded with a 404, then the user could infer that the app exists when they get "permission denied." +// +// 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, + }) + if project != "" { + // The user has provided everything we need to perform an initial RBAC check. + givenRBACName := security.RBACName(s.ns, project, namespace, name) + if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, action, givenRBACName); err != nil { + logCtx.WithFields(map[string]interface{}{ + "project": project, + argocommon.SecurityField: argocommon.SecurityMedium, + }).Warnf("user tried to %s application which they do not have access to: %s", action, err) + // Do a GET on the app. This ensures that the timing of a "no access" response is the same as a "yes access, + // but the app is in a different project" response. We don't want the user inferring the existence of the + // app from response time. + _, _ = getApp() + return nil, permissionDeniedErr + } + } + a, err := getApp() + if err != nil { + if apierr.IsNotFound(err) { + if project != "" { + // We know that the user was allowed to get the Application, but the Application does not exist. Return 404. + return nil, status.Errorf(codes.NotFound, apierr.NewNotFound(schema.GroupResource{Group: "argoproj.io", Resource: "applications"}, name).Error()) + } + // We don't know if the user was allowed to get the Application, and we don't want to leak information about + // the Application's existence. Return 403. + logCtx.Warn("application does not exist") + return nil, permissionDeniedErr + } + logCtx.Errorf("failed to get application: %s", err) + return nil, permissionDeniedErr + } + // Even if we performed an initial RBAC check (because the request was fully parameterized), we still need to + // perform a second RBAC check to ensure that the user has access to the actual Application's project (not just the + // project they specified in the request). + if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, action, a.RBACName(s.ns)); err != nil { + logCtx.WithFields(map[string]interface{}{ + "project": a.Spec.Project, + argocommon.SecurityField: argocommon.SecurityMedium, + }).Warnf("user tried to %s application which they do not have access to: %s", action, err) + if project != "" { + // The user specified a project. We would have returned a 404 if the user had access to the app, but the app + // did not exist. So we have to return a 404 when the app does exist, but the user does not have access. + // Otherwise, they could infer that the app exists based on the error code. + return nil, status.Errorf(codes.NotFound, apierr.NewNotFound(schema.GroupResource{Group: "argoproj.io", Resource: "applications"}, name).Error()) + } + // The user didn't specify a project. We always return permission denied for both lack of access and lack of + // existence. + return nil, permissionDeniedErr + } + effectiveProject := "default" + if a.Spec.Project != "" { + effectiveProject = a.Spec.Project + } + if project != "" && effectiveProject != project { + logCtx.WithFields(map[string]interface{}{ + "project": a.Spec.Project, + argocommon.SecurityField: argocommon.SecurityMedium, + }).Warnf("user tried to %s application in project %s, but the application is in project %s", action, project, effectiveProject) + // The user has access to the app, but the app is in a different project. Return 404, meaning "app doesn't + // exist in that project". + return nil, status.Errorf(codes.NotFound, apierr.NewNotFound(schema.GroupResource{Group: "argoproj.io", Resource: "applications"}, name).Error()) + } + return a, nil +} + +// getApplicationEnforceRBACInformer uses an informer to get an Application. If the app does not exist, permission is +// denied, or any other error occurs when getting the app, we return a permission denied error to obscure any sensitive +// information. +func (s *Server) getApplicationEnforceRBACInformer(ctx context.Context, action, project, namespace, name string) (*appv1.Application, error) { + namespaceOrDefault := s.appNamespaceOrDefault(namespace) + return s.getAppEnforceRBAC(ctx, action, project, namespaceOrDefault, name, func() (*appv1.Application, error) { + return s.appLister.Applications(namespaceOrDefault).Get(name) + }) +} + +// getApplicationEnforceRBACClient uses a client to get an Application. If the app does not exist, permission is denied, +// or any other error occurs when getting the app, we return a permission denied error to obscure any sensitive +// information. +func (s *Server) getApplicationEnforceRBACClient(ctx context.Context, action, project, namespace, name, resourceVersion string) (*appv1.Application, error) { + namespaceOrDefault := s.appNamespaceOrDefault(namespace) + return s.getAppEnforceRBAC(ctx, action, project, namespaceOrDefault, name, func() (*appv1.Application, error) { + if !s.isNamespaceEnabled(namespaceOrDefault) { + return nil, security.NamespaceNotPermittedError(namespaceOrDefault) + } + return s.appclientset.ArgoprojV1alpha1().Applications(namespaceOrDefault).Get(ctx, name, metav1.GetOptions{ + ResourceVersion: resourceVersion, + }) + }) +} + // List returns list of applications func (s *Server) List(ctx context.Context, q *application.ApplicationQuery) (*appv1.ApplicationList, error) { selector, err := labels.Parse(q.GetSelector()) @@ -146,11 +265,24 @@ func (s *Server) List(ctx context.Context, q *application.ApplicationQuery) (*ap if err != nil { return nil, fmt.Errorf("error listing apps with selectors: %w", err) } + + filteredApps := apps + // Filter applications by name + if q.Name != nil { + filteredApps = argoutil.FilterByNameP(filteredApps, *q.Name) + } + + // Filter applications by projects + filteredApps = argoutil.FilterByProjectsP(filteredApps, getProjectsFromApplicationQuery(*q)) + + // Filter applications by source repo URL + filteredApps = argoutil.FilterByRepoP(filteredApps, q.GetRepo()) + newItems := make([]appv1.Application, 0) - for _, a := range apps { - // Skip any application that is neither in the conrol plane's namespace + for _, a := range filteredApps { + // Skip any application that is neither in the control plane's namespace // nor in the list of enabled namespaces. - if a.Namespace != s.ns && !glob.MatchStringInList(s.enabledNamespaces, a.Namespace, false) { + if !s.isNamespaceEnabled(a.Namespace) { continue } if s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)) { @@ -158,19 +290,6 @@ func (s *Server) List(ctx context.Context, q *application.ApplicationQuery) (*ap } } - if q.Name != nil { - newItems, err = argoutil.FilterByName(newItems, *q.Name) - if err != nil { - return nil, fmt.Errorf("error filtering applications by name: %w", err) - } - } - - // Filter applications by name - newItems = argoutil.FilterByProjects(newItems, q.Projects) - - // Filter applications by source repo URL - newItems = argoutil.FilterByRepo(newItems, q.GetRepo()) - // Sort found applications by name sort.Slice(newItems, func(i, j int) bool { return newItems[i].Name < newItems[j].Name @@ -214,15 +333,17 @@ func (s *Server) Create(ctx context.Context, q *application.ApplicationCreateReq return nil, security.NamespaceNotPermittedError(appNs) } + // Don't let the app creator set the operation explicitly. Those requests should always go through the Sync API. + if a.Operation != nil { + log.WithFields(log.Fields{ + "application": a.Name, + argocommon.SecurityField: argocommon.SecurityLow, + }).Warn("User attempted to set operation on application creation. This could have allowed them to bypass branch protection rules by setting manifests directly. Ignoring the set operation.") + a.Operation = nil + } + created, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Create(ctx, a, metav1.CreateOptions{}) if err == nil { - if a.Spec.GetSource().Plugin != nil && a.Spec.GetSource().Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": a.Spec.GetSource().Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } - s.logAppEvent(created, ctx, argo.EventReasonResourceCreated, "created application") s.waitSync(created) return created, nil @@ -325,23 +446,12 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan if q.Name == nil || *q.Name == "" { return nil, fmt.Errorf("invalid request: application name is missing") } - appName := q.GetName() - appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) - a, err := s.appLister.Applications(appNs).Get(appName) + a, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName()) if err != nil { - return nil, fmt.Errorf("error getting application: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil { return nil, err } source := a.Spec.GetSource() - if source.Plugin != nil && source.Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": source.Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } if !s.isNamespaceEnabled(a.Namespace) { return nil, security.NamespaceNotPermittedError(a.Namespace) @@ -359,10 +469,6 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan return fmt.Errorf("error getting app instance label key from settings: %w", err) } - plugins, err := s.plugins() - if err != nil { - return fmt.Errorf("error getting plugins: %w", err) - } config, err := s.getApplicationClusterConfig(ctx, a) if err != nil { return fmt.Errorf("error getting application cluster config: %w", err) @@ -378,6 +484,11 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan return fmt.Errorf("error getting API resources: %w", err) } + proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx) + if err != nil { + return fmt.Errorf("error getting app project: %w", err) + } + manifestInfo, err = client.GenerateManifest(ctx, &apiclient.ManifestRequest{ Repo: repo, Revision: revision, @@ -386,7 +497,6 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan Namespace: a.Spec.Destination.Namespace, ApplicationSource: &source, Repos: helmRepos, - Plugins: plugins, KustomizeOptions: kustomizeOptions, KubeVersion: serverVersion, ApiVersions: argo.APIResourcesToStrings(apiResources, true), @@ -394,6 +504,8 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan HelmOptions: helmOptions, TrackingMethod: string(argoutil.GetTrackingMethod(s.settingsMgr)), EnabledSourceTypes: enableGenerateManifests, + ProjectName: proj.Name, + ProjectSourceRepos: proj.Spec.SourceRepos, }) if err != nil { return fmt.Errorf("error generating manifests: %w", err) @@ -439,14 +551,8 @@ func (s *Server) GetManifestsWithFiles(stream application.ApplicationService_Get return fmt.Errorf("invalid request: application name is missing") } - appName := query.GetName() - appNs := s.appNamespaceOrDefault(query.GetAppNamespace()) - a, err := s.appLister.Applications(appNs).Get(appName) - + a, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, query.GetProject(), query.GetAppNamespace(), query.GetName()) if err != nil { - return fmt.Errorf("error getting application: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil { return err } @@ -459,10 +565,6 @@ func (s *Server) GetManifestsWithFiles(stream application.ApplicationService_Get return fmt.Errorf("error getting app instance label key from settings: %w", err) } - plugins, err := s.plugins() - if err != nil { - return fmt.Errorf("error getting plugins: %w", err) - } config, err := s.getApplicationClusterConfig(ctx, a) if err != nil { return fmt.Errorf("error getting application cluster config: %w", err) @@ -479,6 +581,12 @@ func (s *Server) GetManifestsWithFiles(stream application.ApplicationService_Get } source := a.Spec.GetSource() + + proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx) + if err != nil { + return fmt.Errorf("error getting app project: %w", err) + } + req := &apiclient.ManifestRequest{ Repo: repo, Revision: source.TargetRevision, @@ -487,7 +595,6 @@ func (s *Server) GetManifestsWithFiles(stream application.ApplicationService_Get Namespace: a.Spec.Destination.Namespace, ApplicationSource: &source, Repos: helmRepos, - Plugins: plugins, KustomizeOptions: kustomizeOptions, KubeVersion: serverVersion, ApiVersions: argo.APIResourcesToStrings(apiResources, true), @@ -495,6 +602,8 @@ func (s *Server) GetManifestsWithFiles(stream application.ApplicationService_Get HelmOptions: helmOptions, TrackingMethod: string(argoutil.GetTrackingMethod(s.settingsMgr)), EnabledSourceTypes: enableGenerateManifests, + ProjectName: proj.Name, + ProjectSourceRepos: proj.Spec.SourceRepos, } repoStreamClient, err := client.GenerateManifestWithFiles(stream.Context()) @@ -548,27 +657,22 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app appName := q.GetName() appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) + project := "" + projects := getProjectsFromApplicationQuery(*q) + if len(projects) == 1 { + project = projects[0] + } else if len(projects) > 1 { + return nil, status.Errorf(codes.InvalidArgument, "multiple projects specified - the get endpoint accepts either zero or one project") + } + // We must use a client Get instead of an informer Get, because it's common to call Get immediately // following a Watch (which is not yet powered by an informer), and the Get must reflect what was // previously seen by the client. - a, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{ - ResourceVersion: q.GetResourceVersion(), - }) - + a, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, project, appNs, appName, q.GetResourceVersion()) if err != nil { - return nil, fmt.Errorf("error getting application: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil { return nil, err } - if a.Spec.GetSource().Plugin != nil && a.Spec.GetSource().Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": a.Spec.GetSource().Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } - s.inferResourcesStatusHealth(a) if q.Refresh == nil { @@ -647,23 +751,11 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app // ListResourceEvents returns a list of event resources func (s *Server) ListResourceEvents(ctx context.Context, q *application.ApplicationResourceEventsQuery) (*v1.EventList, error) { - appName := q.GetName() - appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) - a, err := s.appLister.Applications(appNs).Get(appName) + a, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName()) if err != nil { - return nil, fmt.Errorf("error getting application: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil { return nil, err } - if a.Spec.GetSource().Plugin != nil && a.Spec.GetSource().Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": a.Spec.GetSource().Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } - var ( kubeClientset kubernetes.Interface fieldSelector string @@ -721,13 +813,15 @@ func (s *Server) ListResourceEvents(ctx context.Context, q *application.Applicat return list, nil } -func (s *Server) validateAndUpdateApp(ctx context.Context, newApp *appv1.Application, merge bool, validate bool) (*appv1.Application, error) { +// validateAndUpdateApp validates and updates the application. currentProject is the name of the project the app +// currently is under. If not specified, we assume that the app is under the project specified in the app spec. +func (s *Server) validateAndUpdateApp(ctx context.Context, newApp *appv1.Application, merge bool, validate bool, action string, currentProject string) (*appv1.Application, error) { s.projectLock.RLock(newApp.Spec.GetProject()) defer s.projectLock.RUnlock(newApp.Spec.GetProject()) - app, err := s.appclientset.ArgoprojV1alpha1().Applications(newApp.Namespace).Get(ctx, newApp.Name, metav1.GetOptions{}) + app, err := s.getApplicationEnforceRBACClient(ctx, action, currentProject, newApp.Namespace, newApp.Name, "") if err != nil { - return nil, fmt.Errorf("error getting application: %w", err) + return nil, err } err = s.validateAndNormalizeApp(ctx, newApp, validate) @@ -742,19 +836,6 @@ func (s *Server) validateAndUpdateApp(ctx context.Context, newApp *appv1.Applica return a, nil } -func mergeStringMaps(items ...map[string]string) map[string]string { - res := make(map[string]string) - for _, m := range items { - if m == nil { - continue - } - for k, v := range m { - res[k] = v - } - } - return res -} - var informerSyncTimeout = 2 * time.Second // waitSync is a helper to wait until the application informer cache is synced after create/update. @@ -792,8 +873,8 @@ func (s *Server) updateApp(app *appv1.Application, newApp *appv1.Application, ct for i := 0; i < 10; i++ { app.Spec = newApp.Spec if merge { - app.Labels = mergeStringMaps(app.Labels, newApp.Labels) - app.Annotations = mergeStringMaps(app.Annotations, newApp.Annotations) + app.Labels = collections.MergeStringMaps(app.Labels, newApp.Labels) + app.Annotations = collections.MergeStringMaps(app.Annotations, newApp.Annotations) } else { app.Labels = newApp.Labels app.Annotations = newApp.Annotations @@ -823,25 +904,18 @@ func (s *Server) updateApp(app *appv1.Application, newApp *appv1.Application, ct // Update updates an application func (s *Server) Update(ctx context.Context, q *application.ApplicationUpdateRequest) (*appv1.Application, error) { if q.GetApplication() == nil { - return nil, fmt.Errorf("error creating application: application is nil in request") + return nil, fmt.Errorf("error updating application: application is nil in request") } a := q.GetApplication() if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, a.RBACName(s.ns)); err != nil { return nil, err } - if a.Spec.GetSource().Plugin != nil && a.Spec.GetSource().Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": a.Spec.GetSource().Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } - validate := true if q.Validate != nil { validate = *q.Validate } - return s.validateAndUpdateApp(ctx, q.Application, false, validate) + return s.validateAndUpdateApp(ctx, q.Application, false, validate, rbacpolicy.ActionUpdate, q.GetProject()) } // UpdateSpec updates an application spec and filters out any invalid parameter overrides @@ -849,29 +923,17 @@ func (s *Server) UpdateSpec(ctx context.Context, q *application.ApplicationUpdat if q.GetSpec() == nil { return nil, fmt.Errorf("error updating application spec: spec is nil in request") } - appName := q.GetName() - appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) - a, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{}) + a, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionUpdate, q.GetProject(), q.GetAppNamespace(), q.GetName(), "") if err != nil { - return nil, fmt.Errorf("error getting application: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, a.RBACName(s.ns)); err != nil { return nil, err } - if a.Spec.GetSource().Plugin != nil && a.Spec.GetSource().Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": a.Spec.GetSource().Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } - a.Spec = *q.GetSpec() validate := true if q.Validate != nil { validate = *q.Validate } - a, err = s.validateAndUpdateApp(ctx, a, false, validate) + a, err = s.validateAndUpdateApp(ctx, a, false, validate, rbacpolicy.ActionUpdate, q.GetProject()) if err != nil { return nil, fmt.Errorf("error validating and updating app: %w", err) } @@ -880,24 +942,15 @@ func (s *Server) UpdateSpec(ctx context.Context, q *application.ApplicationUpdat // Patch patches an application func (s *Server) Patch(ctx context.Context, q *application.ApplicationPatchRequest) (*appv1.Application, error) { - appName := q.GetName() - appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) - app, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{}) + app, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName(), "") if err != nil { - return nil, fmt.Errorf("error getting application: %w", err) + return nil, err } if err = s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, app.RBACName(s.ns)); err != nil { return nil, err } - if app.Spec.GetSource().Plugin != nil && app.Spec.GetSource().Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": app.Name, - "plugin": app.Spec.GetSource().Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } - jsonApp, err := json.Marshal(app) if err != nil { return nil, fmt.Errorf("error marshaling application: %w", err) @@ -929,16 +982,16 @@ func (s *Server) Patch(ctx context.Context, q *application.ApplicationPatchReque if err != nil { return nil, fmt.Errorf("error unmarshaling patched app: %w", err) } - return s.validateAndUpdateApp(ctx, newApp, false, true) + return s.validateAndUpdateApp(ctx, newApp, false, true, rbacpolicy.ActionUpdate, q.GetProject()) } // Delete removes an application and all associated resources func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteRequest) (*application.ApplicationResponse, error) { appName := q.GetName() appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) - a, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{}) + a, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, q.GetProject(), appNs, appName, "") if err != nil { - return nil, fmt.Errorf("error getting application: %w", err) + return nil, err } s.projectLock.RLock(a.Spec.Project) @@ -948,13 +1001,6 @@ func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteReq return nil, err } - if a.Spec.GetSource().Plugin != nil && a.Spec.GetSource().Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": a.Spec.GetSource().Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } - if q.Cascade != nil && !*q.Cascade && q.GetPropagationPolicy() != "" { return nil, status.Error(codes.InvalidArgument, "cannot set propagation policy when cascading is disabled") } @@ -1003,6 +1049,31 @@ func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteReq return &application.ApplicationResponse{}, nil } +func (s *Server) isApplicationPermitted(selector labels.Selector, minVersion int, claims any, appName, appNs string, projects map[string]bool, a appv1.Application) bool { + if len(projects) > 0 && !projects[a.Spec.GetProject()] { + return false + } + + if appVersion, err := strconv.Atoi(a.ResourceVersion); err == nil && appVersion < minVersion { + return false + } + matchedEvent := (appName == "" || (a.Name == appName && a.Namespace == appNs)) && selector.Matches(labels.Set(a.Labels)) + if !matchedEvent { + return false + } + + if !s.isNamespaceEnabled(a.Namespace) { + return false + } + + if !s.enf.Enforce(claims, rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)) { + // do not emit apps user does not have accessing + return false + } + + return true +} + func (s *Server) Watch(q *application.ApplicationQuery, ws application.ApplicationService_WatchServer) error { appName := q.GetName() appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) @@ -1011,8 +1082,8 @@ func (s *Server) Watch(q *application.ApplicationQuery, ws application.Applicati logCtx = logCtx.WithField("application", *q.Name) } projects := map[string]bool{} - for i := range q.Projects { - projects[q.Projects[i]] = true + for _, project := range getProjectsFromApplicationQuery(*q) { + projects[project] = true } claims := ws.Context().Value("claims") selector, err := labels.Parse(q.GetSelector()) @@ -1029,20 +1100,8 @@ func (s *Server) Watch(q *application.ApplicationQuery, ws application.Applicati // sendIfPermitted is a helper to send the application to the client's streaming channel if the // caller has RBAC privileges permissions to view it sendIfPermitted := func(a appv1.Application, eventType watch.EventType) { - if len(projects) > 0 && !projects[a.Spec.GetProject()] { - return - } - - if appVersion, err := strconv.Atoi(a.ResourceVersion); err == nil && appVersion < minVersion { - return - } - matchedEvent := (appName == "" || (a.Name == appName && a.Namespace == appNs)) && selector.Matches(labels.Set(a.Labels)) - if !matchedEvent { - return - } - - if !s.enf.Enforce(claims, rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)) { - // do not emit apps user does not have accessing + permitted := s.isApplicationPermitted(selector, minVersion, claims, appName, appNs, projects, a) + if !permitted { return } s.inferResourcesStatusHealth(&a) @@ -1089,7 +1148,9 @@ func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Applica proj, err := argo.GetAppProject(app, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx) if err != nil { if apierr.IsNotFound(err) { - return status.Errorf(codes.InvalidArgument, "application references project %s which does not exist", app.Spec.Project) + // Offer no hint that the project does not exist. + log.Warnf("User attempted to create/update application in non-existent project %q", app.Spec.Project) + return permissionDeniedErr } return fmt.Errorf("error getting application's project: %w", err) } @@ -1117,19 +1178,16 @@ func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Applica return err } } - plugins, err := s.plugins() - if err != nil { - return fmt.Errorf("error getting plugins: %w", err) - } if err := argo.ValidateDestination(ctx, &app.Spec.Destination, s.db); err != nil { return status.Errorf(codes.InvalidArgument, "application destination spec for %s is invalid: %s", app.Name, err.Error()) } var conditions []appv1.ApplicationCondition + if validate { conditions := make([]appv1.ApplicationCondition, 0) - condition, err := argo.ValidateRepo(ctx, app, s.repoClientset, s.db, plugins, s.kubectl, proj, s.settingsMgr) + condition, err := argo.ValidateRepo(ctx, app, s.repoClientset, s.db, s.kubectl, proj, s.settingsMgr) if err != nil { return fmt.Errorf("error validating the repo: %w", err) } @@ -1175,9 +1233,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) @@ -1193,22 +1251,16 @@ func (s *Server) getAppResources(ctx context.Context, a *appv1.Application) (*ap return s.cache.GetAppResourcesTree(a.InstanceName(s.ns), &tree) }) if err != nil { - return &tree, fmt.Errorf("error getting cached app state: %w", err) + return &tree, fmt.Errorf("error getting cached app resource tree: %w", err) } return &tree, nil } func (s *Server) getAppLiveResource(ctx context.Context, action string, q *application.ApplicationResourceRequest) (*appv1.ResourceNode, *rest.Config, *appv1.Application, error) { - appName := q.GetName() - appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) - a, err := s.appLister.Applications(appNs).Get(appName) + a, err := s.getApplicationEnforceRBACInformer(ctx, action, q.GetProject(), q.GetAppNamespace(), q.GetName()) if err != nil { - return nil, nil, nil, fmt.Errorf("error getting app by name: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, action, a.RBACName(s.ns)); err != nil { return nil, nil, nil, err } - tree, err := s.getAppResources(ctx, a) if err != nil { return nil, nil, nil, fmt.Errorf("error getting app resources: %w", err) @@ -1228,7 +1280,7 @@ func (s *Server) getAppLiveResource(ctx context.Context, action string, q *appli func (s *Server) GetResource(ctx context.Context, q *application.ApplicationResourceRequest) (*application.ApplicationResourceResponse, error) { res, config, _, err := s.getAppLiveResource(ctx, rbacpolicy.ActionGet, q) if err != nil { - return nil, fmt.Errorf("error getting app live resource: %w", err) + return nil, err } // make sure to use specified resource version if provided @@ -1272,12 +1324,10 @@ func (s *Server) PatchResource(ctx context.Context, q *application.ApplicationRe Kind: q.Kind, Version: q.Version, Group: q.Group, + Project: q.Project, } res, config, a, err := s.getAppLiveResource(ctx, rbacpolicy.ActionUpdate, resourceRequest) if err != nil { - return nil, fmt.Errorf("error getting app live resource: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, a.RBACName(s.ns)); err != nil { return nil, err } @@ -1289,6 +1339,9 @@ func (s *Server) PatchResource(ctx context.Context, q *application.ApplicationRe } return nil, fmt.Errorf("error patching resource: %w", err) } + if manifest == nil { + return nil, fmt.Errorf("failed to patch resource: manifest was nil") + } manifest, err = replaceSecretValues(manifest) if err != nil { return nil, fmt.Errorf("error replacing secret values: %w", err) @@ -1314,12 +1367,10 @@ func (s *Server) DeleteResource(ctx context.Context, q *application.ApplicationR Kind: q.Kind, Version: q.Version, Group: q.Group, + Project: q.Project, } res, config, a, err := s.getAppLiveResource(ctx, rbacpolicy.ActionDelete, resourceRequest) if err != nil { - return nil, fmt.Errorf("error getting live resource for delete: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionDelete, a.RBACName(s.ns)); err != nil { return nil, err } var deleteOption metav1.DeleteOptions @@ -1343,42 +1394,24 @@ func (s *Server) DeleteResource(ctx context.Context, q *application.ApplicationR } func (s *Server) ResourceTree(ctx context.Context, q *application.ResourcesQuery) (*appv1.ApplicationTree, error) { - appName := q.GetApplicationName() - appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) - a, err := s.appLister.Applications(appNs).Get(appName) + a, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetApplicationName()) if err != nil { - return nil, fmt.Errorf("error getting application by name: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil { return nil, err } - source := a.Spec.GetSource() - if source.Plugin != nil && source.Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": source.Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } - return s.getAppResources(ctx, a) } func (s *Server) WatchResourceTree(q *application.ResourcesQuery, ws application.ApplicationService_WatchResourceTreeServer) error { - appName := q.GetApplicationName() - appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) - a, err := s.appLister.Applications(appNs).Get(appName) + _, err := s.getApplicationEnforceRBACInformer(ws.Context(), rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetApplicationName()) if err != nil { - return fmt.Errorf("error getting application by name: %w", err) - } - - if err := s.enf.EnforceErr(ws.Context().Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil { return err } - return s.cache.OnAppResourcesTreeChanged(ws.Context(), q.GetApplicationName(), func() error { + cacheKey := argo.AppInstanceName(q.GetApplicationName(), q.GetAppNamespace(), s.ns) + return s.cache.OnAppResourcesTreeChanged(ws.Context(), cacheKey, func() error { var tree appv1.ApplicationTree - err := s.cache.GetAppResourcesTree(q.GetApplicationName(), &tree) + err := s.cache.GetAppResourcesTree(cacheKey, &tree) if err != nil { return fmt.Errorf("error getting app resource tree: %w", err) } @@ -1387,24 +1420,12 @@ func (s *Server) WatchResourceTree(q *application.ResourcesQuery, ws application } func (s *Server) RevisionMetadata(ctx context.Context, q *application.RevisionMetadataQuery) (*appv1.RevisionMetadata, error) { - appName := q.GetName() - appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) - a, err := s.appLister.Applications(appNs).Get(appName) + a, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName()) if err != nil { - return nil, fmt.Errorf("error getting app by name: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil { return nil, err } source := a.Spec.GetSource() - if source.Plugin != nil && source.Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": source.Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } - repo, err := s.db.GetRepository(ctx, source.RepoURL) if err != nil { return nil, fmt.Errorf("error getting repository by URL: %w", err) @@ -1427,6 +1448,31 @@ func (s *Server) RevisionMetadata(ctx context.Context, q *application.RevisionMe }) } +// RevisionChartDetails returns the helm chart metadata, as fetched from the reposerver +func (s *Server) RevisionChartDetails(ctx context.Context, q *application.RevisionMetadataQuery) (*appv1.ChartDetails, error) { + a, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName()) + if err != nil { + return nil, err + } + if a.Spec.Source.Chart == "" { + return nil, fmt.Errorf("no chart found for application: %v", a.QualifiedName()) + } + repo, err := s.db.GetRepository(ctx, a.Spec.Source.RepoURL) + if err != nil { + return nil, fmt.Errorf("error getting repository by URL: %w", err) + } + conn, repoClient, err := s.repoClientset.NewRepoServerClient() + if err != nil { + return nil, fmt.Errorf("error creating repo server client: %w", err) + } + defer ioutil.Close(conn) + return repoClient.GetRevisionChartDetails(ctx, &apiclient.RepoServerRevisionChartDetailsRequest{ + Repo: repo, + Name: a.Spec.Source.Chart, + Revision: q.GetRevision(), + }) +} + func isMatchingResource(q *application.ResourcesQuery, key kube.ResourceKey) bool { return (q.GetName() == "" || q.GetName() == key.Name) && (q.GetNamespace() == "" || q.GetNamespace() == key.Namespace) && @@ -1435,22 +1481,9 @@ func isMatchingResource(q *application.ResourcesQuery, key kube.ResourceKey) boo } func (s *Server) ManagedResources(ctx context.Context, q *application.ResourcesQuery) (*application.ManagedResourcesResponse, error) { - appName := q.GetApplicationName() - appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) - a, err := s.appLister.Applications(appNs).Get(appName) + a, err := s.getApplicationEnforceRBACInformer(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetApplicationName()) if err != nil { - return nil, fmt.Errorf("error getting application: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil { - return nil, fmt.Errorf("error verifying rbac: %w", err) - } - - source := a.Spec.GetSource() - if source.Plugin != nil && source.Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": source.Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) + return nil, err } items := make([]*appv1.ResourceDiff, 0) @@ -1458,12 +1491,12 @@ func (s *Server) ManagedResources(ctx context.Context, q *application.ResourcesQ return s.cache.GetAppManagedResources(a.InstanceName(s.ns), &items) }) if err != nil { - return nil, fmt.Errorf("error getting cached app state: %w", err) + return nil, fmt.Errorf("error getting cached app managed resources: %w", err) } res := &application.ManagedResourcesResponse{} for i := range items { item := items[i] - if isMatchingResource(q, kube.ResourceKey{Name: item.Name, Namespace: item.Namespace, Kind: item.Kind, Group: item.Group}) { + if !item.Hook && isMatchingResource(q, kube.ResourceKey{Name: item.Name, Namespace: item.Namespace, Kind: item.Kind, Group: item.Group}) { res.Items = append(res.Items, item) } } @@ -1505,25 +1538,11 @@ func (s *Server) PodLogs(q *application.ApplicationPodLogsQuery, ws application. } } - appName := q.GetName() - appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) - a, err := s.appLister.Applications(appNs).Get(appName) + a, err := s.getApplicationEnforceRBACInformer(ws.Context(), rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName()) if err != nil { - return fmt.Errorf("error getting application by name: %w", err) - } - - if err := s.enf.EnforceErr(ws.Context().Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil { return err } - source := a.Spec.GetSource() - if source.Plugin != nil && source.Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": source.Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } - // Logs RBAC will be enforced only if an internal var serverRBACLogEnforceEnable (representing server.rbac.log.enforce.enable env var) // is defined and has a "true" value // Otherwise, no RBAC enforcement for logs will take place (meaning, PodLogs will return the logs, @@ -1690,8 +1709,8 @@ func isTheSelectedOne(currentNode *appv1.ResourceNode, q *application.Applicatio } for _, parentResource := range currentNode.ParentRefs { - //look up parentResource from resourceNodes - //then check if the parent isTheSelectedOne + // look up parentResource from resourceNodes + // then check if the parent isTheSelectedOne for _, resourceNode := range resourceNodes { if resourceNode.Namespace == parentResource.Namespace && resourceNode.Name == parentResource.Name && @@ -1711,12 +1730,9 @@ func isTheSelectedOne(currentNode *appv1.ResourceNode, q *application.Applicatio // Sync syncs an application to its target state func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncRequest) (*appv1.Application, error) { - appName := syncReq.GetName() - appNs := s.appNamespaceOrDefault(syncReq.GetAppNamespace()) - appIf := s.appclientset.ArgoprojV1alpha1().Applications(appNs) - a, err := appIf.Get(ctx, appName, metav1.GetOptions{}) + a, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, syncReq.GetProject(), syncReq.GetAppNamespace(), syncReq.GetName(), "") if err != nil { - return nil, fmt.Errorf("error getting application by name: %w", err) + return nil, err } proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx) @@ -1738,12 +1754,6 @@ func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncR } source := a.Spec.GetSource() - if source.Plugin != nil && source.Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": source.Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } if syncReq.Manifests != nil { if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionOverride, a.RBACName(s.ns)); err != nil { @@ -1756,7 +1766,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) } @@ -1809,6 +1819,9 @@ func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncR op.Retry = *retry } + appName := syncReq.GetName() + appNs := s.appNamespaceOrDefault(syncReq.GetAppNamespace()) + appIf := s.appclientset.ArgoprojV1alpha1().Applications(appNs) a, err = argo.SetAppOperation(appIf, appName, &op) if err != nil { return nil, fmt.Errorf("error setting app operation: %w", err) @@ -1826,25 +1839,11 @@ func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncR } func (s *Server) Rollback(ctx context.Context, rollbackReq *application.ApplicationRollbackRequest) (*appv1.Application, error) { - appName := rollbackReq.GetName() - appNs := s.appNamespaceOrDefault(rollbackReq.GetAppNamespace()) - appIf := s.appclientset.ArgoprojV1alpha1().Applications(appNs) - a, err := appIf.Get(ctx, appName, metav1.GetOptions{}) + a, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionSync, rollbackReq.GetProject(), rollbackReq.GetAppNamespace(), rollbackReq.GetName(), "") if err != nil { - return nil, fmt.Errorf("error getting application by name: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionSync, a.RBACName(s.ns)); err != nil { return nil, err } - source := a.Spec.GetSource() - if source.Plugin != nil && source.Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": source.Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } - s.inferResourcesStatusHealth(a) if a.DeletionTimestamp != nil { @@ -1887,6 +1886,9 @@ func (s *Server) Rollback(ctx context.Context, rollbackReq *application.Applicat }, InitiatedBy: appv1.OperationInitiator{Username: session.Username(ctx)}, } + appName := rollbackReq.GetName() + appNs := s.appNamespaceOrDefault(rollbackReq.GetAppNamespace()) + appIf := s.appclientset.ArgoprojV1alpha1().Applications(appNs) a, err = argo.SetAppOperation(appIf, appName, &op) if err != nil { return nil, fmt.Errorf("error setting app operation: %w", err) @@ -1896,24 +1898,9 @@ func (s *Server) Rollback(ctx context.Context, rollbackReq *application.Applicat } func (s *Server) ListLinks(ctx context.Context, req *application.ListAppLinksRequest) (*application.LinksResponse, error) { - appName := req.GetName() - appNs := s.appNamespaceOrDefault(req.GetNamespace()) - - a, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{}) + a, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, req.GetProject(), req.GetNamespace(), req.GetName(), "") if err != nil { - log.WithFields(map[string]interface{}{ - "application": appName, - "ns": appNs, - }).Errorf("failed to get application, error=%v", err.Error()) - return nil, fmt.Errorf("error getting application") - } - - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil { - log.WithFields(map[string]interface{}{ - "application": appName, - "ns": appNs, - }).Warnf("unauthorized access to app, error=%v", err.Error()) - return nil, fmt.Errorf("error getting application") + return nil, err } obj, err := kube.ToUnstructured(a) @@ -1926,7 +1913,14 @@ func (s *Server) ListLinks(ctx context.Context, req *application.ListAppLinksReq return nil, fmt.Errorf("failed to read application deep links from configmap: %w", err) } - finalList, errorList := deeplinks.EvaluateDeepLinksResponse(*obj, deepLinks) + clstObj, _, err := s.getObjectsForDeepLinks(ctx, a) + if err != nil { + return nil, err + } + + deepLinksObject := deeplinks.CreateDeepLinksObject(nil, obj, clstObj, nil) + + finalList, errorList := deeplinks.EvaluateDeepLinksResponse(deepLinksObject, obj.GetName(), deepLinks) if len(errorList) > 0 { log.Errorf("errorList while evaluating application deep links, %v", strings.Join(errorList, ", ")) } @@ -1934,12 +1928,59 @@ func (s *Server) ListLinks(ctx context.Context, req *application.ListAppLinksReq return finalList, nil } +func (s *Server) getObjectsForDeepLinks(ctx context.Context, app *appv1.Application) (cluster *unstructured.Unstructured, project *unstructured.Unstructured, err error) { + proj, err := argo.GetAppProject(app, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx) + if err != nil { + return nil, nil, fmt.Errorf("error getting app project: %w", err) + } + + // sanitize project jwt tokens + proj.Status = appv1.AppProjectStatus{} + + project, err = kube.ToUnstructured(proj) + if err != nil { + return nil, nil, err + } + + getProjectClusters := func(project string) ([]*appv1.Cluster, error) { + return s.db.GetProjectClusters(ctx, project) + } + + if err := argo.ValidateDestination(ctx, &app.Spec.Destination, s.db); err != nil { + log.WithFields(map[string]interface{}{ + "application": app.GetName(), + "ns": app.GetNamespace(), + "destination": app.Spec.Destination, + }).Warnf("cannot validate cluster, error=%v", err.Error()) + return nil, nil, nil + } + + permitted, err := proj.IsDestinationPermitted(app.Spec.Destination, getProjectClusters) + if err != nil { + return nil, nil, err + } + if !permitted { + return nil, nil, fmt.Errorf("error getting destination cluster") + } + clst, err := s.db.GetCluster(ctx, app.Spec.Destination.Server) + if err != nil { + log.WithFields(map[string]interface{}{ + "application": app.GetName(), + "ns": app.GetNamespace(), + "destination": app.Spec.Destination, + }).Warnf("cannot get cluster from db, error=%v", err.Error()) + return nil, nil, nil + } + // sanitize cluster, remove cluster config creds and other unwanted fields + cluster, err = deeplinks.SanitizeCluster(clst) + return cluster, project, err +} + func (s *Server) ListResourceLinks(ctx context.Context, req *application.ApplicationResourceRequest) (*application.LinksResponse, error) { - obj, _, _, _, err := s.getUnstructuredLiveResourceOrApp(ctx, rbacpolicy.ActionGet, req) + obj, _, app, _, err := s.getUnstructuredLiveResourceOrApp(ctx, rbacpolicy.ActionGet, req) if err != nil { return nil, err } - deepLinks, err := s.settingsMgr.GetDeepLinks(settings.ResourceDeepLinks) if err != nil { return nil, fmt.Errorf("failed to read application deep links from configmap: %w", err) @@ -1950,7 +1991,18 @@ func (s *Server) ListResourceLinks(ctx context.Context, req *application.Applica return nil, fmt.Errorf("error replacing secret values: %w", err) } - finalList, errorList := deeplinks.EvaluateDeepLinksResponse(*obj, deepLinks) + appObj, err := kube.ToUnstructured(app) + if err != nil { + return nil, err + } + + clstObj, projObj, err := s.getObjectsForDeepLinks(ctx, app) + if err != nil { + return nil, err + } + + deepLinksObject := deeplinks.CreateDeepLinksObject(obj, appObj, clstObj, projObj) + finalList, errorList := deeplinks.EvaluateDeepLinksResponse(deepLinksObject, obj.GetName(), deepLinks) if len(errorList) > 0 { log.Errorf("errors while evaluating resource deep links, %v", strings.Join(errorList, ", ")) } @@ -2000,11 +2052,8 @@ func (s *Server) resolveRevision(ctx context.Context, app *appv1.Application, sy func (s *Server) TerminateOperation(ctx context.Context, termOpReq *application.OperationTerminateRequest) (*application.OperationTerminateResponse, error) { appName := termOpReq.GetName() appNs := s.appNamespaceOrDefault(termOpReq.GetAppNamespace()) - a, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{}) + a, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionSync, termOpReq.GetProject(), appNs, appName, "") if err != nil { - return nil, fmt.Errorf("error getting application by name: %w", err) - } - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionSync, a.RBACName(s.ns)); err != nil { return nil, err } @@ -2039,7 +2088,7 @@ func (s *Server) logAppEvent(a *appv1.Application, ctx context.Context, reason s user = "Unknown user" } message := fmt.Sprintf("%s %s", user, action) - s.auditLogger.LogAppEvent(a, eventInfo, message) + s.auditLogger.LogAppEvent(a, eventInfo, message, user) } func (s *Server) logResourceEvent(res *appv1.ResourceNode, ctx context.Context, reason string, action string) { @@ -2049,7 +2098,7 @@ func (s *Server) logResourceEvent(res *appv1.ResourceNode, ctx context.Context, user = "Unknown user" } message := fmt.Sprintf("%s %s", user, action) - s.auditLogger.LogResourceEvent(res, eventInfo, message) + s.auditLogger.LogResourceEvent(res, eventInfo, message, user) } func (s *Server) ListResourceActions(ctx context.Context, q *application.ApplicationResourceRequest) (*application.ResourceActionsListResponse, error) { @@ -2075,11 +2124,10 @@ func (s *Server) ListResourceActions(ctx context.Context, q *application.Applica } func (s *Server) getUnstructuredLiveResourceOrApp(ctx context.Context, rbacRequest string, q *application.ApplicationResourceRequest) (obj *unstructured.Unstructured, res *appv1.ResourceNode, app *appv1.Application, config *rest.Config, err error) { - if q.GetKind() == "Application" && q.GetGroup() == "argoproj.io" && q.GetName() == q.GetResourceName() { - namespace := s.appNamespaceOrDefault(q.GetAppNamespace()) - app, err = s.appLister.Applications(namespace).Get(q.GetName()) + if q.GetKind() == applicationType.ApplicationKind && q.GetGroup() == applicationType.Group && q.GetName() == q.GetResourceName() { + app, err = s.getApplicationEnforceRBACInformer(ctx, rbacRequest, q.GetProject(), q.GetAppNamespace(), q.GetName()) if err != nil { - return nil, nil, nil, nil, fmt.Errorf("error getting app by name: %w", err) + return nil, nil, nil, nil, err } if err = s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacRequest, app.RBACName(s.ns)); err != nil { return nil, nil, nil, nil, err @@ -2092,9 +2140,10 @@ func (s *Server) getUnstructuredLiveResourceOrApp(ctx context.Context, rbacReque } else { res, config, app, err = s.getAppLiveResource(ctx, rbacRequest, q) if err != nil { - return nil, nil, nil, nil, fmt.Errorf("error getting app live resource: %w", err) + return nil, nil, nil, nil, err } obj, err = s.kubectl.GetResource(ctx, config, res.GroupKindVersion(), res.Name, res.Namespace) + } if err != nil { return nil, nil, nil, nil, fmt.Errorf("error getting resource: %w", err) @@ -2131,6 +2180,7 @@ func (s *Server) RunResourceAction(ctx context.Context, q *application.ResourceA Kind: q.Kind, Version: q.Version, Group: q.Group, + Project: q.Project, } actionRequest := fmt.Sprintf("%s/%s/%s/%s", rbacpolicy.ActionAction, q.GetGroup(), q.GetKind(), q.GetAction()) liveObj, res, a, config, err := s.getUnstructuredLiveResourceOrApp(ctx, actionRequest, resourceRequest) @@ -2138,6 +2188,11 @@ func (s *Server) RunResourceAction(ctx context.Context, q *application.ResourceA return nil, err } + liveObjBytes, err := json.Marshal(liveObj) + if err != nil { + return nil, fmt.Errorf("error marshaling live object: %w", err) + } + resourceOverrides, err := s.settingsMgr.GetResourceOverrides() if err != nil { return nil, fmt.Errorf("error getting resource overrides: %w", err) @@ -2151,21 +2206,80 @@ func (s *Server) RunResourceAction(ctx context.Context, q *application.ResourceA return nil, fmt.Errorf("error getting Lua resource action: %w", err) } - newObj, err := luaVM.ExecuteResourceAction(liveObj, action.ActionLua) + newObjects, err := luaVM.ExecuteResourceAction(liveObj, action.ActionLua) if err != nil { return nil, fmt.Errorf("error executing Lua resource action: %w", err) } - newObjBytes, err := json.Marshal(newObj) - if err != nil { - return nil, fmt.Errorf("error marshaling new object: %w", err) + var app *appv1.Application + // Only bother getting the app if we know we're going to need it for a resource permission check. + if len(newObjects) > 0 { + // No need for an RBAC check, we checked above that the user is allowed to run this action. + app, err = s.appLister.Applications(s.appNamespaceOrDefault(q.GetAppNamespace())).Get(q.GetName()) + if err != nil { + return nil, err + } } - liveObjBytes, err := json.Marshal(liveObj) - if err != nil { - return nil, fmt.Errorf("error marshaling live object: %w", err) + // First, make sure all the returned resources are permitted, for each operation. + // Also perform create with dry-runs for all create-operation resources. + // This is performed separately to reduce the risk of only some of the resources being successfully created later. + // TODO: when apply/delete operations would be supported for custom actions, + // the dry-run for relevant apply/delete operation would have to be invoked as well. + for _, impactedResource := range newObjects { + newObj := impactedResource.UnstructuredObj + err := s.verifyResourcePermitted(ctx, app, newObj) + if err != nil { + return nil, err + } + switch impactedResource.K8SOperation { + case lua.CreateOperation: + createOptions := metav1.CreateOptions{DryRun: []string{"All"}} + _, err := s.kubectl.CreateResource(ctx, config, newObj.GroupVersionKind(), newObj.GetName(), newObj.GetNamespace(), newObj, createOptions) + if err != nil { + return nil, err + } + } + } + + // Now, perform the actual operations. + // The creation itself is not transactional. + // TODO: maybe create a k8s list representation of the resources, + // and invoke create on this list resource to make it semi-transactional (there is still patch operation that is separate, + // thus can fail separately from create). + for _, impactedResource := range newObjects { + newObj := impactedResource.UnstructuredObj + newObjBytes, err := json.Marshal(newObj) + + if err != nil { + return nil, fmt.Errorf("error marshaling new object: %w", err) + } + + switch impactedResource.K8SOperation { + // No default case since a not supported operation would have failed upon unmarshaling earlier + case lua.PatchOperation: + _, err := s.patchResource(ctx, config, liveObjBytes, newObjBytes, newObj) + if err != nil { + return nil, err + } + case lua.CreateOperation: + _, err := s.createResource(ctx, config, newObj) + if err != nil { + return nil, err + } + } + } + + if res == nil { + s.logAppEvent(a, ctx, argo.EventReasonResourceActionRan, fmt.Sprintf("ran action %s", q.GetAction())) + } else { + s.logAppEvent(a, ctx, argo.EventReasonResourceActionRan, fmt.Sprintf("ran action %s on resource %s/%s/%s", q.GetAction(), res.Group, res.Kind, res.Name)) + s.logResourceEvent(res, ctx, argo.EventReasonResourceActionRan, fmt.Sprintf("ran action %s", q.GetAction())) } + return &application.ApplicationResponse{}, nil +} +func (s *Server) patchResource(ctx context.Context, config *rest.Config, liveObjBytes, newObjBytes []byte, newObj *unstructured.Unstructured) (*application.ApplicationResponse, error) { diffBytes, err := jsonpatch.CreateMergePatch(liveObjBytes, newObjBytes) if err != nil { return nil, fmt.Errorf("error calculating merge patch: %w", err) @@ -2205,12 +2319,38 @@ func (s *Server) RunResourceAction(ctx context.Context, q *application.ResourceA return nil, fmt.Errorf("error patching resource: %w", err) } } + return &application.ApplicationResponse{}, nil +} - if res == nil { - s.logAppEvent(a, ctx, argo.EventReasonResourceActionRan, fmt.Sprintf("ran action %s", q.GetAction())) - } else { - s.logAppEvent(a, ctx, argo.EventReasonResourceActionRan, fmt.Sprintf("ran action %s on resource %s/%s/%s", q.GetAction(), res.Group, res.Kind, res.Name)) - s.logResourceEvent(res, ctx, argo.EventReasonResourceActionRan, fmt.Sprintf("ran action %s", q.GetAction())) +func (s *Server) verifyResourcePermitted(ctx context.Context, app *appv1.Application, obj *unstructured.Unstructured) error { + proj, err := argo.GetAppProject(app, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx) + if err != nil { + if apierr.IsNotFound(err) { + return fmt.Errorf("application references project %s which does not exist", app.Spec.Project) + } + return fmt.Errorf("failed to get project %s: %w", app.Spec.Project, err) + } + permitted, err := proj.IsResourcePermitted(schema.GroupKind{Group: obj.GroupVersionKind().Group, Kind: obj.GroupVersionKind().Kind}, obj.GetNamespace(), app.Spec.Destination, func(project string) ([]*appv1.Cluster, error) { + clusters, err := s.db.GetProjectClusters(context.TODO(), project) + if err != nil { + return nil, fmt.Errorf("failed to get project clusters: %w", err) + } + return clusters, nil + }) + if err != nil { + return fmt.Errorf("error checking resource permissions: %w", err) + } + if !permitted { + return fmt.Errorf("application %s is not permitted to manage %s/%s/%s in %s", app.RBACName(s.ns), obj.GroupVersionKind().Group, obj.GroupVersionKind().Kind, obj.GetName(), obj.GetNamespace()) + } + + return nil +} + +func (s *Server) createResource(ctx context.Context, config *rest.Config, newObj *unstructured.Unstructured) (*application.ApplicationResponse, error) { + _, err := s.kubectl.CreateResource(ctx, config, newObj.GroupVersionKind(), newObj.GetName(), newObj.GetNamespace(), newObj, metav1.CreateOptions{}) + if err != nil { + return nil, fmt.Errorf("error creating resource: %w", err) } return &application.ApplicationResponse{}, nil } @@ -2248,40 +2388,12 @@ func splitStatusPatch(patch []byte) ([]byte, []byte, error) { return nonStatusPatch, statusPatch, nil } -func (s *Server) plugins() ([]*appv1.ConfigManagementPlugin, error) { - plugins, err := s.settingsMgr.GetConfigManagementPlugins() - if err != nil { - return nil, fmt.Errorf("error getting config management plugin: %w", err) - } - tools := make([]*appv1.ConfigManagementPlugin, len(plugins)) - for i, p := range plugins { - p := p - tools[i] = &p - } - return tools, nil -} - func (s *Server) GetApplicationSyncWindows(ctx context.Context, q *application.ApplicationSyncWindowsQuery) (*application.ApplicationSyncWindowsResponse, error) { - appName := q.GetName() - appNs := s.appNamespaceOrDefault(q.GetAppNamespace()) - appIf := s.appclientset.ArgoprojV1alpha1().Applications(appNs) - a, err := appIf.Get(ctx, appName, metav1.GetOptions{}) + a, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, q.GetProject(), q.GetAppNamespace(), q.GetName(), "") if err != nil { - return nil, fmt.Errorf("error getting application by name: %w", err) - } - - if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil { return nil, err } - source := a.Spec.GetSource() - if source.Plugin != nil && source.Plugin.Name != "" { - log.WithFields(map[string]interface{}{ - "application": a.Name, - "plugin": source.Plugin.Name, - }).Warnf(argocommon.ConfigMapPluginDeprecationWarning) - } - proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx) if err != nil { return nil, fmt.Errorf("error getting app project: %w", err) @@ -2358,3 +2470,12 @@ func (s *Server) appNamespaceOrDefault(appNs string) string { func (s *Server) isNamespaceEnabled(namespace string) bool { return security.IsNamespaceEnabled(namespace, s.ns, s.enabledNamespaces) } + +// getProjectFromApplicationQuery gets the project names from a query. If the legacy "project" field was specified, use +// that. Otherwise, use the newer "projects" field. +func getProjectsFromApplicationQuery(q application.ApplicationQuery) []string { + if q.Project != nil { + return q.Project + } + return q.Projects +} diff --git a/server/application/application.proto b/server/application/application.proto index 4fb08a7082c0f..4736219cb4594 100644 --- a/server/application/application.proto +++ b/server/application/application.proto @@ -13,11 +13,15 @@ import "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1/generated.p import "github.com/argoproj/argo-cd/v2/reposerver/repository/repository.proto"; -// ApplicationQuery is a query for application resources +// ApplicationQuery is a query for application resources. When getting multiple applications, the "projects" field acts +// as a filter. When getting a single application, you may specify either zero or one project. If you specify zero +// projects, the application will be returned regardless of which project it belongs to (assuming you have access). If +// you specify one project, the application will only be returned if it exists and belongs to the specified project. +// Otherwise you will receive a 404. 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; @@ -29,6 +33,8 @@ message ApplicationQuery { optional string repo = 6; // the application's namespace optional string appNamespace = 7; + // the project names to restrict returned list applications (legacy name for backwards-compatibility) + repeated string project = 8; } message NodeQuery { @@ -44,6 +50,7 @@ message RevisionMetadataQuery{ required string revision = 2; // the application's namespace optional string appNamespace = 3; + optional string project = 4; } // ApplicationEventsQuery is a query for application resource events @@ -53,6 +60,7 @@ message ApplicationResourceEventsQuery { optional string resourceName = 3; optional string resourceUID = 4; optional string appNamespace = 5; + optional string project = 6; } // ManifestQuery is a query for manifest resources @@ -60,6 +68,7 @@ message ApplicationManifestQuery { required string name = 1; optional string revision = 2; optional string appNamespace = 3; + optional string project = 4; } message FileChunk { @@ -70,6 +79,7 @@ message ApplicationManifestQueryWithFiles { required string name = 1; required string checksum = 2; optional string appNamespace = 3; + optional string project = 4; } message ApplicationManifestQueryWithFilesWrapper { @@ -90,6 +100,7 @@ message ApplicationCreateRequest { message ApplicationUpdateRequest { required github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Application application = 1; optional bool validate = 2; + optional string project = 3; } message ApplicationDeleteRequest { @@ -97,6 +108,7 @@ message ApplicationDeleteRequest { optional bool cascade = 2; optional string propagationPolicy = 3; optional string appNamespace = 4; + optional string project = 5; } message SyncOptions { @@ -116,6 +128,7 @@ message ApplicationSyncRequest { optional github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.RetryStrategy retryStrategy = 10; optional SyncOptions syncOptions = 11; optional string appNamespace = 12; + optional string project = 13; } // ApplicationUpdateSpecRequest is a request to update application spec @@ -124,6 +137,7 @@ message ApplicationUpdateSpecRequest { required github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSpec spec = 2; optional bool validate = 3; optional string appNamespace = 4; + optional string project = 5; } // ApplicationPatchRequest is a request to patch an application @@ -132,6 +146,7 @@ message ApplicationPatchRequest { required string patch = 2; required string patchType = 3; optional string appNamespace = 5; + optional string project = 6; } message ApplicationRollbackRequest { @@ -140,6 +155,7 @@ message ApplicationRollbackRequest { optional bool dryRun = 3; optional bool prune = 4; optional string appNamespace = 6; + optional string project = 7; } message ApplicationResourceRequest { @@ -150,6 +166,7 @@ message ApplicationResourceRequest { optional string group = 5; required string kind = 6; optional string appNamespace = 7; + optional string project = 8; } message ApplicationResourcePatchRequest { @@ -162,6 +179,7 @@ message ApplicationResourcePatchRequest { required string patch = 7; required string patchType = 8; optional string appNamespace = 9; + optional string project = 10; } message ApplicationResourceDeleteRequest { @@ -174,6 +192,7 @@ message ApplicationResourceDeleteRequest { optional bool force = 7; optional bool orphan = 8; optional string appNamespace = 9; + optional string project = 10; } message ResourceActionRunRequest { @@ -185,6 +204,7 @@ message ResourceActionRunRequest { required string kind = 6; required string action = 7; optional string appNamespace = 8; + optional string project = 9; } message ResourceActionsListResponse { @@ -211,6 +231,7 @@ message ApplicationPodLogsQuery { optional string resourceName = 13 ; optional bool previous = 14; optional string appNamespace = 15; + optional string project = 16; } message LogEntry { @@ -225,11 +246,13 @@ message LogEntry { message OperationTerminateRequest { required string name = 1; optional string appNamespace = 2; + optional string project = 3; } message ApplicationSyncWindowsQuery { required string name = 1; optional string appNamespace = 2; + optional string project = 3; } message ApplicationSyncWindowsResponse { @@ -258,6 +281,7 @@ message ResourcesQuery { optional string group = 5; optional string kind = 6; optional string appNamespace = 7; + optional string project = 8; } message ManagedResourcesResponse { @@ -278,6 +302,7 @@ message LinksResponse { message ListAppLinksRequest { required string name = 1; optional string namespace = 3; + optional string project = 4; } @@ -322,6 +347,11 @@ service ApplicationService { option (google.api.http).get = "/api/v1/applications/{name}/revisions/{revision}/metadata"; } + // Get the chart metadata (description, maintainers, home) for a specific revision of the application + rpc RevisionChartDetails (RevisionMetadataQuery) returns (github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ChartDetails) { + option (google.api.http).get = "/api/v1/applications/{name}/revisions/{revision}/chartdetails"; + } + // GetManifests returns application manifests rpc GetManifests (ApplicationManifestQuery) returns (repository.ManifestResponse) { option (google.api.http).get = "/api/v1/applications/{name}/manifests"; diff --git a/server/application/application_test.go b/server/application/application_test.go index 7569734d33b42..51c912ff05109 100644 --- a/server/application/application_test.go +++ b/server/application/application_test.go @@ -4,30 +4,41 @@ import ( "context" coreerrors "errors" "fmt" + "io" + "strconv" "sync/atomic" "testing" "time" + "k8s.io/apimachinery/pkg/labels" + "github.com/argoproj/gitops-engine/pkg/health" 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/argoproj/pkg/sync" - "github.com/ghodss/yaml" "github.com/golang-jwt/jwt/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + k8sappsv1 "k8s.io/api/apps/v1" + k8sbatchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1" - apierrors "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/runtime/schema" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/rest" kubetesting "k8s.io/client-go/testing" k8scache "k8s.io/client-go/tools/cache" "k8s.io/utils/pointer" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" @@ -36,6 +47,7 @@ import ( appinformer "github.com/argoproj/argo-cd/v2/pkg/client/informers/externalversions" "github.com/argoproj/argo-cd/v2/reposerver/apiclient" "github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks" + appmocks "github.com/argoproj/argo-cd/v2/server/application/mocks" servercache "github.com/argoproj/argo-cd/v2/server/cache" "github.com/argoproj/argo-cd/v2/server/rbacpolicy" "github.com/argoproj/argo-cd/v2/test" @@ -64,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{}, } @@ -78,14 +90,14 @@ func fakeAppList() *apiclient.AppList { } } -func fakeResolveRevesionResponse() *apiclient.ResolveRevisionResponse { +func fakeResolveRevisionResponse() *apiclient.ResolveRevisionResponse { return &apiclient.ResolveRevisionResponse{ Revision: "f9ba9e98119bf8c1176fbd65dbae26a71d044add", AmbiguousRevision: "HEAD (f9ba9e98119bf8c1176fbd65dbae26a71d044add)", } } -func fakeResolveRevesionResponseHelm() *apiclient.ResolveRevisionResponse { +func fakeResolveRevisionResponseHelm() *apiclient.ResolveRevisionResponse { return &apiclient.ResolveRevisionResponse{ Revision: "0.7.*", AmbiguousRevision: "0.7.* (0.7.2)", @@ -98,26 +110,32 @@ func fakeRepoServerClient(isHelm bool) *mocks.RepoServerServiceClient { mockRepoServiceClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(&apiclient.ManifestResponse{}, nil) mockRepoServiceClient.On("GetAppDetails", mock.Anything, mock.Anything).Return(&apiclient.RepoAppDetailsResponse{}, nil) mockRepoServiceClient.On("TestRepository", mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil) + mockRepoServiceClient.On("GetRevisionMetadata", mock.Anything, mock.Anything).Return(&appsv1.RevisionMetadata{}, nil) + mockWithFilesClient := &mocks.RepoServerService_GenerateManifestWithFilesClient{} + mockWithFilesClient.On("Send", mock.Anything).Return(nil) + mockWithFilesClient.On("CloseAndRecv").Return(&apiclient.ManifestResponse{}, nil) + mockRepoServiceClient.On("GenerateManifestWithFiles", mock.Anything, mock.Anything).Return(mockWithFilesClient, nil) + mockRepoServiceClient.On("GetRevisionChartDetails", mock.Anything, mock.Anything).Return(&appsv1.ChartDetails{}, nil) if isHelm { - mockRepoServiceClient.On("ResolveRevision", mock.Anything, mock.Anything).Return(fakeResolveRevesionResponseHelm(), nil) + mockRepoServiceClient.On("ResolveRevision", mock.Anything, mock.Anything).Return(fakeResolveRevisionResponseHelm(), nil) } else { - mockRepoServiceClient.On("ResolveRevision", mock.Anything, mock.Anything).Return(fakeResolveRevesionResponse(), nil) + mockRepoServiceClient.On("ResolveRevision", mock.Anything, mock.Anything).Return(fakeResolveRevisionResponse(), nil) } return &mockRepoServiceClient } // return an ApplicationServiceServer which returns fake data -func newTestAppServer(objects ...runtime.Object) *Server { +func newTestAppServer(t *testing.T, objects ...runtime.Object) *Server { f := func(enf *rbac.Enforcer) { _ = enf.SetBuiltinPolicy(assets.BuiltinPolicyCSV) enf.SetDefaultRole("role:admin") } - return newTestAppServerWithEnforcerConfigure(f, objects...) + return newTestAppServerWithEnforcerConfigure(f, t, objects...) } -func newTestAppServerWithEnforcerConfigure(f func(*rbac.Enforcer), objects ...runtime.Object) *Server { +func newTestAppServerWithEnforcerConfigure(f func(*rbac.Enforcer), t *testing.T, objects ...runtime.Object) *Server { kubeclientset := fake.NewSimpleClientset(&v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: testNamespace, @@ -152,6 +170,7 @@ func newTestAppServerWithEnforcerConfigure(f func(*rbac.Enforcer), objects ...ru Destinations: []appsv1.ApplicationDestination{{Server: "*", Namespace: "*"}}, }, } + myProj := &appsv1.AppProject{ ObjectMeta: metav1.ObjectMeta{Name: "my-proj", Namespace: "default"}, Spec: appsv1.AppProjectSpec{ @@ -190,7 +209,187 @@ func newTestAppServerWithEnforcerConfigure(f func(*rbac.Enforcer), objects ...ru // 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") + } + + projInformer := factory.Argoproj().V1alpha1().AppProjects().Informer() + go projInformer.Run(ctx.Done()) + if !k8scache.WaitForCacheSync(ctx.Done(), projInformer.HasSynced) { + panic("Timed out waiting for caches to sync") + } + + broadcaster := new(appmocks.Broadcaster) + broadcaster.On("Subscribe", mock.Anything, mock.Anything).Return(func() {}).Run(func(args mock.Arguments) { + // Simulate the broadcaster notifying the subscriber of an application update. + // The second parameter to Subscribe is filters. For the purposes of tests, we ignore the filters. Future tests + // might require implementing those. + go func() { + events := args.Get(0).(chan *appsv1.ApplicationWatchEvent) + for _, obj := range objects { + app, ok := obj.(*appsv1.Application) + if ok { + oldVersion, err := strconv.Atoi(app.ResourceVersion) + if err != nil { + oldVersion = 0 + } + clonedApp := app.DeepCopy() + clonedApp.ResourceVersion = fmt.Sprintf("%d", oldVersion+1) + events <- &appsv1.ApplicationWatchEvent{Type: watch.Added, Application: *clonedApp} + } + } + }() + }) + broadcaster.On("OnAdd", mock.Anything).Return() + broadcaster.On("OnUpdate", mock.Anything, mock.Anything).Return() + broadcaster.On("OnDelete", mock.Anything).Return() + + appStateCache := appstate.NewCache(cache.NewCache(cache.NewInMemoryCache(time.Hour)), time.Hour) + // pre-populate the app cache + for _, obj := range objects { + app, ok := obj.(*appsv1.Application) + if ok { + err := appStateCache.SetAppManagedResources(app.Name, []*appsv1.ResourceDiff{}) + require.NoError(t, err) + + // Pre-populate the resource tree based on the app's resources. + nodes := make([]appsv1.ResourceNode, len(app.Status.Resources)) + for i, res := range app.Status.Resources { + nodes[i] = appsv1.ResourceNode{ + ResourceRef: appsv1.ResourceRef{ + Group: res.Group, + Kind: res.Kind, + Version: res.Version, + Name: res.Name, + Namespace: res.Namespace, + UID: "fake", + }, + } + } + err = appStateCache.SetAppResourcesTree(app.Name, &appsv1.ApplicationTree{ + Nodes: nodes, + }) + require.NoError(t, err) + } + } + appCache := servercache.NewCache(appStateCache, time.Hour, time.Hour, time.Hour) + + kubectl := &kubetest.MockKubectlCmd{} + kubectl = kubectl.WithGetResourceFunc(func(_ context.Context, _ *rest.Config, gvk schema.GroupVersionKind, name string, namespace string) (*unstructured.Unstructured, error) { + for _, obj := range objects { + if obj.GetObjectKind().GroupVersionKind().GroupKind() == gvk.GroupKind() { + if obj, ok := obj.(*unstructured.Unstructured); ok && obj.GetName() == name && obj.GetNamespace() == namespace { + return obj, nil + } + } + } + return nil, nil + }) + + server, _ := NewServer( + testNamespace, + kubeclientset, + fakeAppsClientset, + factory.Argoproj().V1alpha1().Applications().Lister(), + appInformer, + broadcaster, + mockRepoClient, + appCache, + kubectl, + db, + enforcer, + sync.NewKeyLock(), + settingsMgr, + projInformer, + []string{}, + ) + return server.(*Server) +} + +// return an ApplicationServiceServer which returns fake data +func newTestAppServerWithBenchmark(b *testing.B, objects ...runtime.Object) *Server { + f := func(enf *rbac.Enforcer) { + _ = enf.SetBuiltinPolicy(assets.BuiltinPolicyCSV) + enf.SetDefaultRole("role:admin") + } + return newTestAppServerWithEnforcerConfigureWithBenchmark(f, b, objects...) +} + +func newTestAppServerWithEnforcerConfigureWithBenchmark(f func(*rbac.Enforcer), b *testing.B, objects ...runtime.Object) *Server { + kubeclientset := fake.NewSimpleClientset(&v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + Name: "argocd-cm", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + }, &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-secret", + Namespace: testNamespace, + }, + Data: map[string][]byte{ + "admin.password": []byte("test"), + "server.secretkey": []byte("test"), + }, + }) + ctx := context.Background() + db := db.NewDB(testNamespace, settings.NewSettingsManager(ctx, kubeclientset, testNamespace), kubeclientset) + _, err := db.CreateRepository(ctx, fakeRepo()) + require.NoError(b, err) + _, err = db.CreateCluster(ctx, fakeCluster()) + require.NoError(b, err) + + mockRepoClient := &mocks.Clientset{RepoServerServiceClient: fakeRepoServerClient(false)} + + defaultProj := &appsv1.AppProject{ + ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "default"}, + Spec: appsv1.AppProjectSpec{ + SourceRepos: []string{"*"}, + Destinations: []appsv1.ApplicationDestination{{Server: "*", Namespace: "*"}}, + }, + } + myProj := &appsv1.AppProject{ + ObjectMeta: metav1.ObjectMeta{Name: "my-proj", Namespace: "default"}, + Spec: appsv1.AppProjectSpec{ + SourceRepos: []string{"*"}, + Destinations: []appsv1.ApplicationDestination{{Server: "*", Namespace: "*"}}, + }, + } + projWithSyncWindows := &appsv1.AppProject{ + ObjectMeta: metav1.ObjectMeta{Name: "proj-maint", Namespace: "default"}, + Spec: appsv1.AppProjectSpec{ + SourceRepos: []string{"*"}, + Destinations: []appsv1.ApplicationDestination{{Server: "*", Namespace: "*"}}, + SyncWindows: appsv1.SyncWindows{}, + }, + } + matchingWindow := &appsv1.SyncWindow{ + Kind: "allow", + Schedule: "* * * * *", + Duration: "1h", + Applications: []string{"test-app"}, + } + projWithSyncWindows.Spec.SyncWindows = append(projWithSyncWindows.Spec.SyncWindows, matchingWindow) + + objects = append(objects, defaultProj, myProj, projWithSyncWindows) + + fakeAppsClientset := apps.NewSimpleClientset(objects...) + factory := appinformer.NewSharedInformerFactoryWithOptions(fakeAppsClientset, 0, appinformer.WithNamespace(""), appinformer.WithTweakListOptions(func(options *metav1.ListOptions) {})) + fakeProjLister := factory.Argoproj().V1alpha1().AppProjects().Lister().AppProjects(testNamespace) + + enforcer := rbac.NewEnforcer(kubeclientset, testNamespace, common.ArgoCDRBACConfigMapName, nil) + f(enforcer) + enforcer.SetClaimsEnforcerFunc(rbacpolicy.NewRBACPolicyEnforcer(enforcer, fakeProjLister).EnforceClaims) + + settingsMgr := settings.NewSettingsManager(ctx, kubeclientset, testNamespace) + + // populate the app informer with the fake objects + appInformer := factory.Argoproj().V1alpha1().Applications().Informer() + go appInformer.Run(ctx.Done()) if !k8scache.WaitForCacheSync(ctx.Done(), appInformer.HasSynced) { panic("Timed out waiting for caches to sync") @@ -202,15 +401,83 @@ func newTestAppServerWithEnforcerConfigure(f func(*rbac.Enforcer), objects ...ru panic("Timed out waiting for caches to sync") } + broadcaster := new(appmocks.Broadcaster) + broadcaster.On("Subscribe", mock.Anything, mock.Anything).Return(func() {}).Run(func(args mock.Arguments) { + // Simulate the broadcaster notifying the subscriber of an application update. + // The second parameter to Subscribe is filters. For the purposes of tests, we ignore the filters. Future tests + // might require implementing those. + go func() { + events := args.Get(0).(chan *appsv1.ApplicationWatchEvent) + for _, obj := range objects { + app, ok := obj.(*appsv1.Application) + if ok { + oldVersion, err := strconv.Atoi(app.ResourceVersion) + if err != nil { + oldVersion = 0 + } + clonedApp := app.DeepCopy() + clonedApp.ResourceVersion = fmt.Sprintf("%d", oldVersion+1) + events <- &appsv1.ApplicationWatchEvent{Type: watch.Added, Application: *clonedApp} + } + } + }() + }) + broadcaster.On("OnAdd", mock.Anything).Return() + broadcaster.On("OnUpdate", mock.Anything, mock.Anything).Return() + broadcaster.On("OnDelete", mock.Anything).Return() + + appStateCache := appstate.NewCache(cache.NewCache(cache.NewInMemoryCache(time.Hour)), time.Hour) + // pre-populate the app cache + for _, obj := range objects { + app, ok := obj.(*appsv1.Application) + if ok { + err := appStateCache.SetAppManagedResources(app.Name, []*appsv1.ResourceDiff{}) + require.NoError(b, err) + + // Pre-populate the resource tree based on the app's resources. + nodes := make([]appsv1.ResourceNode, len(app.Status.Resources)) + for i, res := range app.Status.Resources { + nodes[i] = appsv1.ResourceNode{ + ResourceRef: appsv1.ResourceRef{ + Group: res.Group, + Kind: res.Kind, + Version: res.Version, + Name: res.Name, + Namespace: res.Namespace, + UID: "fake", + }, + } + } + err = appStateCache.SetAppResourcesTree(app.Name, &appsv1.ApplicationTree{ + Nodes: nodes, + }) + require.NoError(b, err) + } + } + appCache := servercache.NewCache(appStateCache, time.Hour, time.Hour, time.Hour) + + kubectl := &kubetest.MockKubectlCmd{} + kubectl = kubectl.WithGetResourceFunc(func(_ context.Context, _ *rest.Config, gvk schema.GroupVersionKind, name string, namespace string) (*unstructured.Unstructured, error) { + for _, obj := range objects { + if obj.GetObjectKind().GroupVersionKind().GroupKind() == gvk.GroupKind() { + if obj, ok := obj.(*unstructured.Unstructured); ok && obj.GetName() == name && obj.GetNamespace() == namespace { + return obj, nil + } + } + } + return nil, nil + }) + server, _ := NewServer( testNamespace, kubeclientset, fakeAppsClientset, factory.Argoproj().V1alpha1().Applications().Lister(), appInformer, + broadcaster, mockRepoClient, - nil, - &kubetest.MockKubectlCmd{}, + appCache, + kubectl, db, enforcer, sync.NewKeyLock(), @@ -236,7 +503,7 @@ spec: environment: default destination: namespace: ` + test.FakeDestNamespace + ` - server: https://cluster-api.com + server: https://cluster-api.example.com ` const fakeAppWithDestName = ` @@ -274,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 { @@ -301,8 +568,512 @@ func createTestApp(testApp string, opts ...func(app *appsv1.Application)) *appsv return &app } +type TestServerStream struct { + ctx context.Context + appName string + headerSent bool + project string +} + +func (t *TestServerStream) SetHeader(metadata.MD) error { + return nil +} + +func (t *TestServerStream) SendHeader(metadata.MD) error { + return nil +} + +func (t *TestServerStream) SetTrailer(metadata.MD) {} + +func (t *TestServerStream) Context() context.Context { + return t.ctx +} + +func (t *TestServerStream) SendMsg(m interface{}) error { + return nil +} + +func (t *TestServerStream) RecvMsg(m interface{}) error { + return nil +} + +func (t *TestServerStream) SendAndClose(r *apiclient.ManifestResponse) error { + return nil +} + +func (t *TestServerStream) Recv() (*application.ApplicationManifestQueryWithFilesWrapper, error) { + if !t.headerSent { + t.headerSent = true + return &application.ApplicationManifestQueryWithFilesWrapper{Part: &application.ApplicationManifestQueryWithFilesWrapper_Query{ + Query: &application.ApplicationManifestQueryWithFiles{ + Name: pointer.String(t.appName), + Project: pointer.String(t.project), + Checksum: pointer.String(""), + }, + }}, nil + } + return nil, io.EOF +} + +func (t *TestServerStream) ServerStream() TestServerStream { + return TestServerStream{} +} + +type TestResourceTreeServer struct { + ctx context.Context +} + +func (t *TestResourceTreeServer) Send(tree *appsv1.ApplicationTree) error { + return nil +} + +func (t *TestResourceTreeServer) SetHeader(metadata.MD) error { + return nil +} + +func (t *TestResourceTreeServer) SendHeader(metadata.MD) error { + return nil +} + +func (t *TestResourceTreeServer) SetTrailer(metadata.MD) {} + +func (t *TestResourceTreeServer) Context() context.Context { + return t.ctx +} + +func (t *TestResourceTreeServer) SendMsg(m interface{}) error { + return nil +} + +func (t *TestResourceTreeServer) RecvMsg(m interface{}) error { + return nil +} + +type TestPodLogsServer struct { + ctx context.Context +} + +func (t *TestPodLogsServer) Send(log *application.LogEntry) error { + return nil +} + +func (t *TestPodLogsServer) SetHeader(metadata.MD) error { + return nil +} + +func (t *TestPodLogsServer) SendHeader(metadata.MD) error { + return nil +} + +func (t *TestPodLogsServer) SetTrailer(metadata.MD) {} + +func (t *TestPodLogsServer) Context() context.Context { + return t.ctx +} + +func (t *TestPodLogsServer) SendMsg(m interface{}) error { + return nil +} + +func (t *TestPodLogsServer) RecvMsg(m interface{}) error { + return nil +} + +func TestNoAppEnumeration(t *testing.T) { + // This test ensures that malicious users can't infer the existence or non-existence of Applications by inspecting + // error messages. The errors for "app does not exist" must be the same as errors for "you aren't allowed to + // interact with this app." + + // These tests are only important on API calls where the full app RBAC name (project, namespace, and name) is _not_ + // known based on the query parameters. For example, the Create call cannot leak existence of Applications, because + // the Application's project, namespace, and name are all specified in the API call. The call can be rejected + // immediately if the user does not have access. But the Delete endpoint may be called with just the Application + // name. So we cannot return a different error message for "does not exist" and "you don't have delete permissions," + // because the user could infer that the Application exists if they do not get the "does not exist" message. For + // endpoints that do not require the full RBAC name, we must return a generic "permission denied" for both "does not + // exist" and "no access." + + f := func(enf *rbac.Enforcer) { + _ = enf.SetBuiltinPolicy(assets.BuiltinPolicyCSV) + enf.SetDefaultRole("role:none") + } + deployment := k8sappsv1.Deployment{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "apps/v1", + Kind: "Deployment", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "test", + }, + } + testApp := newTestApp(func(app *appsv1.Application) { + app.Name = "test" + app.Status.Resources = []appsv1.ResourceStatus{ + { + Group: deployment.GroupVersionKind().Group, + Kind: deployment.GroupVersionKind().Kind, + Version: deployment.GroupVersionKind().Version, + Name: deployment.Name, + Namespace: deployment.Namespace, + Status: "Synced", + }, + } + app.Status.History = []appsv1.RevisionHistory{ + { + ID: 0, + Source: appsv1.ApplicationSource{ + TargetRevision: "something-old", + }, + }, + } + }) + testHelmApp := newTestApp(func(app *appsv1.Application) { + app.Name = "test-helm" + app.Spec.Source.Path = "" + app.Spec.Source.Chart = "test" + app.Status.Resources = []appsv1.ResourceStatus{ + { + Group: deployment.GroupVersionKind().Group, + Kind: deployment.GroupVersionKind().Kind, + Version: deployment.GroupVersionKind().Version, + Name: deployment.Name, + Namespace: deployment.Namespace, + Status: "Synced", + }, + } + app.Status.History = []appsv1.RevisionHistory{ + { + ID: 0, + Source: appsv1.ApplicationSource{ + TargetRevision: "something-old", + }, + }, + } + }) + testDeployment := kube.MustToUnstructured(&deployment) + appServer := newTestAppServerWithEnforcerConfigure(f, t, testApp, testHelmApp, testDeployment) + + noRoleCtx := context.Background() + // nolint:staticcheck + adminCtx := context.WithValue(noRoleCtx, "claims", &jwt.MapClaims{"groups": []string{"admin"}}) + + t.Run("Get", func(t *testing.T) { + // nolint:staticcheck + _, err := appServer.Get(adminCtx, &application.ApplicationQuery{Name: pointer.String("test")}) + assert.NoError(t, err) + // nolint:staticcheck + _, err = appServer.Get(noRoleCtx, &application.ApplicationQuery{Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + // nolint:staticcheck + _, err = appServer.Get(adminCtx, &application.ApplicationQuery{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + // nolint:staticcheck + _, err = appServer.Get(adminCtx, &application.ApplicationQuery{Name: pointer.String("doest-not-exist"), Project: []string{"test"}}) + 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") + }) + + t.Run("GetManifests", func(t *testing.T) { + _, err := appServer.GetManifests(adminCtx, &application.ApplicationManifestQuery{Name: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.GetManifests(noRoleCtx, &application.ApplicationManifestQuery{Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.GetManifests(adminCtx, &application.ApplicationManifestQuery{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.GetManifests(adminCtx, &application.ApplicationManifestQuery{Name: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + t.Run("ListResourceEvents", func(t *testing.T) { + _, err := appServer.ListResourceEvents(adminCtx, &application.ApplicationResourceEventsQuery{Name: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.ListResourceEvents(noRoleCtx, &application.ApplicationResourceEventsQuery{Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ListResourceEvents(adminCtx, &application.ApplicationResourceEventsQuery{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ListResourceEvents(adminCtx, &application.ApplicationResourceEventsQuery{Name: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + 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.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.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.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.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") + }) + + t.Run("Patch", func(t *testing.T) { + _, err := appServer.Patch(adminCtx, &application.ApplicationPatchRequest{Name: pointer.String("test"), Patch: pointer.String(`[{"op": "replace", "path": "/spec/source/path", "value": "foo"}]`)}) + assert.NoError(t, err) + _, err = appServer.Patch(noRoleCtx, &application.ApplicationPatchRequest{Name: pointer.String("test"), Patch: pointer.String(`[{"op": "replace", "path": "/spec/source/path", "value": "foo"}]`)}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.Patch(adminCtx, &application.ApplicationPatchRequest{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.Patch(adminCtx, &application.ApplicationPatchRequest{Name: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + t.Run("GetResource", func(t *testing.T) { + _, err := appServer.GetResource(adminCtx, &application.ApplicationResourceRequest{Name: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.GetResource(noRoleCtx, &application.ApplicationResourceRequest{Name: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.GetResource(adminCtx, &application.ApplicationResourceRequest{Name: pointer.String("doest-not-exist"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.GetResource(adminCtx, &application.ApplicationResourceRequest{Name: pointer.String("doest-not-exist"), Project: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test")}) + 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") + }) + + t.Run("PatchResource", func(t *testing.T) { + _, err := appServer.PatchResource(adminCtx, &application.ApplicationResourcePatchRequest{Name: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test"), Patch: pointer.String(`[{"op": "replace", "path": "/spec/replicas", "value": 3}]`)}) + // This will always throw an error, because the kubectl mock for PatchResource is hard-coded to return nil. + // The best we can do is to confirm we get past the permission check. + assert.NotEqual(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.PatchResource(noRoleCtx, &application.ApplicationResourcePatchRequest{Name: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test"), Patch: pointer.String(`[{"op": "replace", "path": "/spec/replicas", "value": 3}]`)}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.PatchResource(adminCtx, &application.ApplicationResourcePatchRequest{Name: pointer.String("doest-not-exist"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test"), Patch: pointer.String(`[{"op": "replace", "path": "/spec/replicas", "value": 3}]`)}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.PatchResource(adminCtx, &application.ApplicationResourcePatchRequest{Name: pointer.String("doest-not-exist"), Project: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test"), Patch: pointer.String(`[{"op": "replace", "path": "/spec/replicas", "value": 3}]`)}) + 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") + }) + + t.Run("DeleteResource", func(t *testing.T) { + _, err := appServer.DeleteResource(adminCtx, &application.ApplicationResourceDeleteRequest{Name: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.DeleteResource(noRoleCtx, &application.ApplicationResourceDeleteRequest{Name: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.DeleteResource(adminCtx, &application.ApplicationResourceDeleteRequest{Name: pointer.String("doest-not-exist"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.DeleteResource(adminCtx, &application.ApplicationResourceDeleteRequest{Name: pointer.String("doest-not-exist"), Project: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test")}) + 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") + }) + + t.Run("ResourceTree", func(t *testing.T) { + _, err := appServer.ResourceTree(adminCtx, &application.ResourcesQuery{ApplicationName: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.ResourceTree(noRoleCtx, &application.ResourcesQuery{ApplicationName: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ResourceTree(adminCtx, &application.ResourcesQuery{ApplicationName: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ResourceTree(adminCtx, &application.ResourcesQuery{ApplicationName: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + t.Run("RevisionMetadata", func(t *testing.T) { + _, err := appServer.RevisionMetadata(adminCtx, &application.RevisionMetadataQuery{Name: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.RevisionMetadata(noRoleCtx, &application.RevisionMetadataQuery{Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.RevisionMetadata(adminCtx, &application.RevisionMetadataQuery{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.RevisionMetadata(adminCtx, &application.RevisionMetadataQuery{Name: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + t.Run("RevisionChartDetails", func(t *testing.T) { + _, err := appServer.RevisionChartDetails(adminCtx, &application.RevisionMetadataQuery{Name: pointer.String("test-helm")}) + assert.NoError(t, err) + _, err = appServer.RevisionChartDetails(noRoleCtx, &application.RevisionMetadataQuery{Name: pointer.String("test-helm")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.RevisionChartDetails(adminCtx, &application.RevisionMetadataQuery{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.RevisionChartDetails(adminCtx, &application.RevisionMetadataQuery{Name: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + t.Run("ManagedResources", func(t *testing.T) { + _, err := appServer.ManagedResources(adminCtx, &application.ResourcesQuery{ApplicationName: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.ManagedResources(noRoleCtx, &application.ResourcesQuery{ApplicationName: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ManagedResources(adminCtx, &application.ResourcesQuery{ApplicationName: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ManagedResources(adminCtx, &application.ResourcesQuery{ApplicationName: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + t.Run("Sync", func(t *testing.T) { + _, err := appServer.Sync(adminCtx, &application.ApplicationSyncRequest{Name: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.Sync(noRoleCtx, &application.ApplicationSyncRequest{Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.Sync(adminCtx, &application.ApplicationSyncRequest{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.Sync(adminCtx, &application.ApplicationSyncRequest{Name: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + t.Run("TerminateOperation", func(t *testing.T) { + // The sync operation is already started from the previous test. We just need to set the field that the + // controller would set if this were an actual Argo CD environment. + setSyncRunningOperationState(t, appServer) + _, err := appServer.TerminateOperation(adminCtx, &application.OperationTerminateRequest{Name: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.TerminateOperation(noRoleCtx, &application.OperationTerminateRequest{Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.TerminateOperation(adminCtx, &application.OperationTerminateRequest{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.TerminateOperation(adminCtx, &application.OperationTerminateRequest{Name: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + t.Run("Rollback", func(t *testing.T) { + unsetSyncRunningOperationState(t, appServer) + _, err := appServer.Rollback(adminCtx, &application.ApplicationRollbackRequest{Name: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.Rollback(noRoleCtx, &application.ApplicationRollbackRequest{Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.Rollback(adminCtx, &application.ApplicationRollbackRequest{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.Rollback(adminCtx, &application.ApplicationRollbackRequest{Name: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + t.Run("ListResourceActions", func(t *testing.T) { + _, err := appServer.ListResourceActions(adminCtx, &application.ApplicationResourceRequest{Name: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.ListResourceActions(noRoleCtx, &application.ApplicationResourceRequest{Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ListResourceActions(noRoleCtx, &application.ApplicationResourceRequest{Group: pointer.String("argoproj.io"), Kind: pointer.String("Application"), Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ListResourceActions(adminCtx, &application.ApplicationResourceRequest{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ListResourceActions(adminCtx, &application.ApplicationResourceRequest{Name: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + t.Run("RunResourceAction", func(t *testing.T) { + _, err := appServer.RunResourceAction(adminCtx, &application.ResourceActionRunRequest{Name: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test"), Action: pointer.String("restart")}) + assert.NoError(t, err) + _, err = appServer.RunResourceAction(noRoleCtx, &application.ResourceActionRunRequest{Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.RunResourceAction(noRoleCtx, &application.ResourceActionRunRequest{Group: pointer.String("argoproj.io"), Kind: pointer.String("Application"), Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.RunResourceAction(adminCtx, &application.ResourceActionRunRequest{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.RunResourceAction(adminCtx, &application.ResourceActionRunRequest{Name: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + t.Run("GetApplicationSyncWindows", func(t *testing.T) { + _, err := appServer.GetApplicationSyncWindows(adminCtx, &application.ApplicationSyncWindowsQuery{Name: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.GetApplicationSyncWindows(noRoleCtx, &application.ApplicationSyncWindowsQuery{Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.GetApplicationSyncWindows(adminCtx, &application.ApplicationSyncWindowsQuery{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.GetApplicationSyncWindows(adminCtx, &application.ApplicationSyncWindowsQuery{Name: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) + + t.Run("GetManifestsWithFiles", func(t *testing.T) { + err := appServer.GetManifestsWithFiles(&TestServerStream{ctx: adminCtx, appName: "test"}) + assert.NoError(t, err) + err = appServer.GetManifestsWithFiles(&TestServerStream{ctx: noRoleCtx, appName: "test"}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + err = appServer.GetManifestsWithFiles(&TestServerStream{ctx: adminCtx, appName: "does-not-exist"}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + err = appServer.GetManifestsWithFiles(&TestServerStream{ctx: adminCtx, appName: "does-not-exist", project: "test"}) + assert.Equal(t, "rpc error: code = NotFound desc = applications.argoproj.io \"does-not-exist\" not found", err.Error(), "when the request specifies a project, we can return the standard k8s error message") + }) + + t.Run("WatchResourceTree", func(t *testing.T) { + err := appServer.WatchResourceTree(&application.ResourcesQuery{ApplicationName: pointer.String("test")}, &TestResourceTreeServer{ctx: adminCtx}) + assert.NoError(t, err) + err = appServer.WatchResourceTree(&application.ResourcesQuery{ApplicationName: pointer.String("test")}, &TestResourceTreeServer{ctx: noRoleCtx}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + err = appServer.WatchResourceTree(&application.ResourcesQuery{ApplicationName: pointer.String("does-not-exist")}, &TestResourceTreeServer{ctx: adminCtx}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + err = appServer.WatchResourceTree(&application.ResourcesQuery{ApplicationName: pointer.String("does-not-exist"), Project: pointer.String("test")}, &TestResourceTreeServer{ctx: adminCtx}) + assert.Equal(t, "rpc error: code = NotFound desc = applications.argoproj.io \"does-not-exist\" not found", err.Error(), "when the request specifies a project, we can return the standard k8s error message") + }) + + t.Run("PodLogs", func(t *testing.T) { + err := appServer.PodLogs(&application.ApplicationPodLogsQuery{Name: pointer.String("test")}, &TestPodLogsServer{ctx: adminCtx}) + assert.NoError(t, err) + err = appServer.PodLogs(&application.ApplicationPodLogsQuery{Name: pointer.String("test")}, &TestPodLogsServer{ctx: noRoleCtx}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + err = appServer.PodLogs(&application.ApplicationPodLogsQuery{Name: pointer.String("does-not-exist")}, &TestPodLogsServer{ctx: adminCtx}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + err = appServer.PodLogs(&application.ApplicationPodLogsQuery{Name: pointer.String("does-not-exist"), Project: pointer.String("test")}, &TestPodLogsServer{ctx: adminCtx}) + assert.Equal(t, "rpc error: code = NotFound desc = applications.argoproj.io \"does-not-exist\" not found", err.Error(), "when the request specifies a project, we can return the standard k8s error message") + }) + + t.Run("ListLinks", func(t *testing.T) { + _, err := appServer.ListLinks(adminCtx, &application.ListAppLinksRequest{Name: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.ListLinks(noRoleCtx, &application.ListAppLinksRequest{Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ListLinks(adminCtx, &application.ListAppLinksRequest{Name: pointer.String("does-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ListLinks(adminCtx, &application.ListAppLinksRequest{Name: pointer.String("does-not-exist"), Project: pointer.String("test")}) + assert.Equal(t, "rpc error: code = NotFound desc = applications.argoproj.io \"does-not-exist\" not found", err.Error(), "when the request specifies a project, we can return the standard k8s error message") + }) + + t.Run("ListResourceLinks", func(t *testing.T) { + _, err := appServer.ListResourceLinks(adminCtx, &application.ApplicationResourceRequest{Name: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.ListResourceLinks(noRoleCtx, &application.ApplicationResourceRequest{Name: pointer.String("test"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ListResourceLinks(adminCtx, &application.ApplicationResourceRequest{Name: pointer.String("does-not-exist"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.ListResourceLinks(adminCtx, &application.ApplicationResourceRequest{Name: pointer.String("does-not-exist"), ResourceName: pointer.String("test"), Group: pointer.String("apps"), Kind: pointer.String("Deployment"), Namespace: pointer.String("test"), Project: pointer.String("test")}) + assert.Equal(t, "rpc error: code = NotFound desc = applications.argoproj.io \"does-not-exist\" not found", err.Error(), "when the request specifies a project, we can return the standard k8s error message") + }) + + // Do this last so other stuff doesn't fail. + t.Run("Delete", func(t *testing.T) { + _, err := appServer.Delete(adminCtx, &application.ApplicationDeleteRequest{Name: pointer.String("test")}) + assert.NoError(t, err) + _, err = appServer.Delete(noRoleCtx, &application.ApplicationDeleteRequest{Name: pointer.String("test")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.Delete(adminCtx, &application.ApplicationDeleteRequest{Name: pointer.String("doest-not-exist")}) + assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") + _, err = appServer.Delete(adminCtx, &application.ApplicationDeleteRequest{Name: pointer.String("doest-not-exist"), Project: pointer.String("test")}) + 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") + }) +} + +// setSyncRunningOperationState simulates starting a sync operation on the given app. +func setSyncRunningOperationState(t *testing.T, appServer *Server) { + appIf := appServer.appclientset.ArgoprojV1alpha1().Applications("default") + app, err := appIf.Get(context.Background(), "test", metav1.GetOptions{}) + require.NoError(t, err) + // This sets the status that would be set by the controller usually. + app.Status.OperationState = &appsv1.OperationState{Phase: synccommon.OperationRunning, Operation: appsv1.Operation{Sync: &appsv1.SyncOperation{}}} + _, err = appIf.Update(context.Background(), app, metav1.UpdateOptions{}) + require.NoError(t, err) +} + +// unsetSyncRunningOperationState simulates finishing a sync operation on the given app. +func unsetSyncRunningOperationState(t *testing.T, appServer *Server) { + appIf := appServer.appclientset.ArgoprojV1alpha1().Applications("default") + app, err := appIf.Get(context.Background(), "test", metav1.GetOptions{}) + require.NoError(t, err) + app.Operation = nil + app.Status.OperationState = nil + _, err = appIf.Update(context.Background(), app, metav1.UpdateOptions{}) + require.NoError(t, err) +} + func TestListAppsInNamespaceWithLabels(t *testing.T) { - appServer := newTestAppServer(newTestApp(func(app *appsv1.Application) { + appServer := newTestAppServer(t, newTestApp(func(app *appsv1.Application) { app.Name = "App1" app.ObjectMeta.Namespace = "test-namespace" app.SetLabels(map[string]string{"key1": "value1", "key2": "value1"}) @@ -323,7 +1094,7 @@ func TestListAppsInNamespaceWithLabels(t *testing.T) { } func TestListAppsInDefaultNSWithLabels(t *testing.T) { - appServer := newTestAppServer(newTestApp(func(app *appsv1.Application) { + appServer := newTestAppServer(t, newTestApp(func(app *appsv1.Application) { app.Name = "App1" app.SetLabels(map[string]string{"key1": "value1", "key2": "value1"}) }), newTestApp(func(app *appsv1.Application) { @@ -365,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 @@ -391,7 +1162,7 @@ func testListAppsWithLabels(t *testing.T, appQuery application.ApplicationQuery, label: "key1= minVersion { return @@ -344,5 +355,17 @@ func (s *Server) logAppSetEvent(a *v1alpha1.ApplicationSet, ctx context.Context, user = "Unknown user" } message := fmt.Sprintf("%s %s", user, action) - s.auditLogger.LogAppSetEvent(a, eventInfo, message) + s.auditLogger.LogAppSetEvent(a, eventInfo, message, user) +} + +func (s *Server) appsetNamespaceOrDefault(appNs string) string { + if appNs == "" { + return s.ns + } else { + return appNs + } +} + +func (s *Server) isNamespaceEnabled(namespace string) bool { + return security.IsNamespaceEnabled(namespace, s.ns, s.enabledNamespaces) } diff --git a/server/applicationset/applicationset.proto b/server/applicationset/applicationset.proto index 8f6d09cf2b75b..2a857d41a00ce 100644 --- a/server/applicationset/applicationset.proto +++ b/server/applicationset/applicationset.proto @@ -14,6 +14,8 @@ import "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1/generated.p message ApplicationSetGetQuery { // the applicationsets's name string name = 1; + // The application set namespace. Default empty is argocd control plane namespace + string appsetNamespace = 2; } message ApplicationSetListQuery { @@ -21,6 +23,8 @@ message ApplicationSetListQuery { repeated string projects = 1; // the selector to restrict returned list to applications only with matched labels string selector = 2; + // The application set namespace. Default empty is argocd control plane namespace + string appsetNamespace = 3; } @@ -38,6 +42,8 @@ message ApplicationSetCreateRequest { message ApplicationSetDeleteRequest { string name = 1; + // The application set namespace. Default empty is argocd control plane namespace + string appsetNamespace = 2; } diff --git a/server/applicationset/applicationset_test.go b/server/applicationset/applicationset_test.go new file mode 100644 index 0000000000000..c49ddb35a7970 --- /dev/null +++ b/server/applicationset/applicationset_test.go @@ -0,0 +1,476 @@ +package applicationset + +import ( + "context" + "testing" + + "github.com/argoproj/pkg/sync" + "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes/fake" + k8scache "k8s.io/client-go/tools/cache" + + "github.com/argoproj/argo-cd/v2/common" + "github.com/argoproj/argo-cd/v2/pkg/apiclient/applicationset" + appsv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + apps "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/fake" + appinformer "github.com/argoproj/argo-cd/v2/pkg/client/informers/externalversions" + "github.com/argoproj/argo-cd/v2/server/rbacpolicy" + "github.com/argoproj/argo-cd/v2/util/assets" + "github.com/argoproj/argo-cd/v2/util/db" + "github.com/argoproj/argo-cd/v2/util/errors" + "github.com/argoproj/argo-cd/v2/util/rbac" + "github.com/argoproj/argo-cd/v2/util/settings" +) + +const ( + testNamespace = "default" + fakeRepoURL = "https://git.com/repo.git" +) + +func fakeRepo() *appsv1.Repository { + return &appsv1.Repository{ + Repo: fakeRepoURL, + } +} + +func fakeCluster() *appsv1.Cluster { + return &appsv1.Cluster{ + Server: "https://cluster-api.example.com", + Name: "fake-cluster", + Config: appsv1.ClusterConfig{}, + } +} + +// return an ApplicationServiceServer which returns fake data +func newTestAppSetServer(objects ...runtime.Object) *Server { + f := func(enf *rbac.Enforcer) { + _ = enf.SetBuiltinPolicy(assets.BuiltinPolicyCSV) + enf.SetDefaultRole("role:admin") + } + scopedNamespaces := "" + return newTestAppSetServerWithEnforcerConfigure(f, scopedNamespaces, objects...) +} + +// 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, + Name: "argocd-cm", + Labels: map[string]string{ + "app.kubernetes.io/part-of": "argocd", + }, + }, + }, &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "argocd-secret", + Namespace: testNamespace, + }, + Data: map[string][]byte{ + "admin.password": []byte("test"), + "server.secretkey": []byte("test"), + }, + }) + ctx := context.Background() + db := db.NewDB(testNamespace, settings.NewSettingsManager(ctx, kubeclientset, testNamespace), kubeclientset) + _, err := db.CreateRepository(ctx, fakeRepo()) + errors.CheckError(err) + _, err = db.CreateCluster(ctx, fakeCluster()) + errors.CheckError(err) + + defaultProj := &appsv1.AppProject{ + ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "default"}, + Spec: appsv1.AppProjectSpec{ + SourceRepos: []string{"*"}, + Destinations: []appsv1.ApplicationDestination{{Server: "*", Namespace: "*"}}, + }, + } + myProj := &appsv1.AppProject{ + ObjectMeta: metav1.ObjectMeta{Name: "my-proj", Namespace: "default"}, + Spec: appsv1.AppProjectSpec{ + SourceRepos: []string{"*"}, + Destinations: []appsv1.ApplicationDestination{{Server: "*", Namespace: "*"}}, + }, + } + + objects = append(objects, defaultProj, myProj) + + fakeAppsClientset := apps.NewSimpleClientset(objects...) + 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) + f(enforcer) + enforcer.SetClaimsEnforcerFunc(rbacpolicy.NewRBACPolicyEnforcer(enforcer, fakeProjLister).EnforceClaims) + + settingsMgr := settings.NewSettingsManager(ctx, kubeclientset, testNamespace) + + // 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()) + go appInformer.Run(ctx.Done()) + 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()) + if !k8scache.WaitForCacheSync(ctx.Done(), projInformer.HasSynced) { + panic("Timed out waiting for caches to sync") + } + + server := NewServer( + db, + kubeclientset, + enforcer, + fakeAppsClientset, + appInformer, + factory.Argoproj().V1alpha1().ApplicationSets().Lister(), + fakeProjLister, + settingsMgr, + testNamespace, + sync.NewKeyLock(), + []string{testNamespace, "external-namespace"}, + ) + return server.(*Server) +} + +func newTestAppSet(opts ...func(appset *appsv1.ApplicationSet)) *appsv1.ApplicationSet { + appset := appsv1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testNamespace, + }, + Spec: appsv1.ApplicationSetSpec{ + Template: appsv1.ApplicationSetTemplate{ + Spec: appsv1.ApplicationSpec{ + Project: "default", + }, + }, + }, + } + for i := range opts { + opts[i](&appset) + } + return &appset +} + +func testListAppsetsWithLabels(t *testing.T, appsetQuery applicationset.ApplicationSetListQuery, appServer *Server) { + validTests := []struct { + testName string + label string + expectedResult []string + }{ + {testName: "Equality based filtering using '=' operator", + label: "key1=value1", + expectedResult: []string{"AppSet1"}}, + {testName: "Equality based filtering using '==' operator", + label: "key1==value1", + expectedResult: []string{"AppSet1"}}, + {testName: "Equality based filtering using '!=' operator", + label: "key1!=value1", + expectedResult: []string{"AppSet2", "AppSet3"}}, + {testName: "Set based filtering using 'in' operator", + label: "key1 in (value1, value3)", + expectedResult: []string{"AppSet1", "AppSet3"}}, + {testName: "Set based filtering using 'notin' operator", + label: "key1 notin (value1, value3)", + expectedResult: []string{"AppSet2"}}, + {testName: "Set based filtering using 'exists' operator", + label: "key1", + expectedResult: []string{"AppSet1", "AppSet2", "AppSet3"}}, + {testName: "Set based filtering using 'not exists' operator", + label: "!key2", + expectedResult: []string{"AppSet2", "AppSet3"}}, + } + //test valid scenarios + for _, validTest := range validTests { + t.Run(validTest.testName, func(t *testing.T) { + appsetQuery.Selector = validTest.label + res, err := appServer.List(context.Background(), &appsetQuery) + assert.NoError(t, err) + apps := []string{} + for i := range res.Items { + apps = append(apps, res.Items[i].Name) + } + assert.Equal(t, validTest.expectedResult, apps) + }) + } + + invalidTests := []struct { + testName string + label string + errorMesage string + }{ + {testName: "Set based filtering using '>' operator", + label: "key1>value1", + errorMesage: "error parsing the selector"}, + {testName: "Set based filtering using '<' operator", + label: "key1]*>([^<]*)`) rightTextPattern = regexp.MustCompile(`id="rightText" [^>]*>([^<]*)`) revisionTextPattern = regexp.MustCompile(`id="revisionText" [^>]*>([^<]*)`) + titleTextPattern = regexp.MustCompile(`id="titleText" [^>]*>([^<]*)`) + titleRectWidthPattern = regexp.MustCompile(`(id="titleRect" .* width=)("0")`) + rightRectWidthPattern = regexp.MustCompile(`(id="rightRect" .* width=)("\d*")`) + leftRectYCoodPattern = regexp.MustCompile(`(id="leftRect" .* y=)("\d*")`) + rightRectYCoodPattern = regexp.MustCompile(`(id="rightRect" .* y=)("\d*")`) + revisionRectYCoodPattern = regexp.MustCompile(`(id="revisionRect" .* y=)("\d*")`) + leftTextYCoodPattern = regexp.MustCompile(`(id="leftText" .* y=)("\d*")`) + rightTextYCoodPattern = regexp.MustCompile(`(id="rightText" .* y=)("\d*")`) + revisionTextYCoodPattern = regexp.MustCompile(`(id="revisionText" .* y=)("\d*")`) + svgHeightPattern = regexp.MustCompile(`^( 0 && len(errs) != 0 { + w.WriteHeader(http.StatusBadRequest) + return + } + } + if apps, err := h.appClientset.ArgoprojV1alpha1().Applications(reqNs).List(context.Background(), v1.ListOptions{}); err == nil { applicationSet := argo.FilterByProjects(apps.Items, projects) for _, a := range applicationSet { if a.Status.Sync.Status != appv1.SyncStatusCodeSynced { @@ -143,6 +197,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if !notFound && revisionEnabled && revision != "" { // Increase width of SVG and enable display of revision components badge = svgWidthPattern.ReplaceAllString(badge, fmt.Sprintf(`:" + // Example: + // Argocd-Application-Name: "namespace:app-name" + HeaderArgoCDApplicationName = "Argocd-Application-Name" + + // HeaderArgoCDProjectName defines the name of the expected + // project header to be passed to the extension handler. + // Example: + // Argocd-Project-Name: "default" + HeaderArgoCDProjectName = "Argocd-Project-Name" + + // HeaderArgoCDTargetClusterURL defines the target cluster URL + // that the Argo CD application is associated with. This header + // will be populated by the extension proxy and passed to the + // configured backend service. If this header is passed by + // the client, its value will be overriden by the extension + // handler. + // + // Example: + // Argocd-Target-Cluster-URL: "https://kubernetes.default.svc.cluster.local" + HeaderArgoCDTargetClusterURL = "Argocd-Target-Cluster-URL" + + // HeaderArgoCDTargetClusterName defines the target cluster name + // that the Argo CD application is associated with. This header + // will be populated by the extension proxy and passed to the + // configured backend service. If this header is passed by + // the client, its value will be overriden by the extension + // handler. + HeaderArgoCDTargetClusterName = "Argocd-Target-Cluster-Name" ) +// RequestResources defines the authorization scope for +// an incoming request to a given extension. This struct +// is populated from pre-defined Argo CD headers. +type RequestResources struct { + ApplicationName string + ApplicationNamespace string + ProjectName string +} + +// ValidateHeaders will validate the pre-defined Argo CD +// request headers for extensions and extract the resources +// information populating and returning a RequestResources +// object. +// The pre-defined headers are: +// - Argocd-Application-Name +// - Argocd-Project-Name +// +// The headers expected format is documented in each of the constant +// types defined for them. +func ValidateHeaders(r *http.Request) (*RequestResources, error) { + appHeader := r.Header.Get(HeaderArgoCDApplicationName) + if appHeader == "" { + return nil, fmt.Errorf("header %q must be provided", HeaderArgoCDApplicationName) + } + appNamespace, appName, err := getAppName(appHeader) + if err != nil { + return nil, fmt.Errorf("error getting app details: %s", err) + } + if !argo.IsValidNamespaceName(appNamespace) { + return nil, errors.New("invalid value for namespace") + } + if !argo.IsValidAppName(appName) { + return nil, errors.New("invalid value for application name") + } + + projName := r.Header.Get(HeaderArgoCDProjectName) + if projName == "" { + return nil, fmt.Errorf("header %q must be provided", HeaderArgoCDProjectName) + } + if !argo.IsValidProjectName(projName) { + return nil, errors.New("invalid value for project name") + } + return &RequestResources{ + ApplicationName: appName, + ApplicationNamespace: appNamespace, + ProjectName: projName, + }, nil +} + +func getAppName(appHeader string) (string, string, error) { + parts := strings.Split(appHeader, ":") + if len(parts) != 2 { + return "", "", fmt.Errorf("invalid value for %q header: expected format: :", HeaderArgoCDApplicationName) + } + return parts[0], parts[1], nil +} + // ExtensionConfigs defines the configurations for all extensions // retrieved from Argo CD configmap (argocd-cm). type ExtensionConfigs struct { - Extensions []ExtensionConfig `json:"extensions"` + Extensions []ExtensionConfig `yaml:"extensions"` } // ExtensionConfig defines the configuration for one extension. type ExtensionConfig struct { // Name defines the endpoint that will be used to register // the extension route. Mandatory field. - Name string `json:"name"` - Backend BackendConfig `json:"backend"` + Name string `yaml:"name"` + Backend BackendConfig `yaml:"backend"` } // BackendConfig defines the backend service configurations that will @@ -51,7 +144,47 @@ type ExtensionConfig struct { // service. type BackendConfig struct { ProxyConfig - Services []ServiceConfig `json:"services"` + Services []ServiceConfig `yaml:"services"` +} + +// ServiceConfig provides the configuration for a backend service. +type ServiceConfig struct { + // URL is the address where the extension backend must be available. + // Mandatory field. + URL string `yaml:"url"` + + // Cluster if provided, will have to match the application + // destination name to have requests properly forwarded to this + // service URL. + Cluster *ClusterConfig `yaml:"cluster,omitempty"` + + // Headers if provided, the headers list will be added on all + // outgoing requests for this service config. + Headers []Header `yaml:"headers"` +} + +// Header defines the header to be added in the proxy requests. +type Header struct { + // Name defines the name of the header. It is a mandatory field if + // a header is provided. + Name string `yaml:"name"` + // Value defines the value of the header. The actual value can be + // provided as verbatim or as a reference to an Argo CD secret key. + // In order to provide it as a reference, it is necessary to prefix + // it with a dollar sign. + // Example: + // value: '$some.argocd.secret.key' + // In the example above, the value will be replaced with the one from + // the argocd-secret with key 'some.argocd.secret.key'. + Value string `yaml:"value"` +} + +type ClusterConfig struct { + // Server specifies the URL of the target cluster's Kubernetes control plane API. This must be set if Name is not set. + Server string `yaml:"server"` + + // Name is an alternate way of specifying the target cluster by its symbolic name. This must be set if Server is not set. + Name string `yaml:"name"` } // ProxyConfig allows configuring connection behaviour between Argo CD @@ -60,36 +193,24 @@ type ProxyConfig struct { // ConnectionTimeout is the maximum amount of time a dial to // the extension server will wait for a connect to complete. // Default: 2 seconds - ConnectionTimeout time.Duration `json:"connectionTimeout"` + ConnectionTimeout time.Duration `yaml:"connectionTimeout"` // KeepAlive specifies the interval between keep-alive probes // for an active network connection between the API server and // the extension server. // Default: 15 seconds - KeepAlive time.Duration `json:"keepAlive"` + KeepAlive time.Duration `yaml:"keepAlive"` // IdleConnectionTimeout is the maximum amount of time an idle // (keep-alive) connection between the API server and the extension // server will remain idle before closing itself. // Default: 60 seconds - IdleConnectionTimeout time.Duration `json:"idleConnectionTimeout"` + IdleConnectionTimeout time.Duration `yaml:"idleConnectionTimeout"` // MaxIdleConnections controls the maximum number of idle (keep-alive) // connections between the API server and the extension server. // Default: 30 - MaxIdleConnections int `json:"maxIdleConnections"` -} - -// ServiceConfig provides the configuration for a backend service. -type ServiceConfig struct { - // URL is the address where the extension backend must be available. - // Mandatory field. - URL string `json:"url"` - - // Cluster if provided, will have to match the application - // destination name to have requests properly forwarded to this - // service URL. - Cluster string `json:"cluster"` + MaxIdleConnections int `yaml:"maxIdleConnections"` } // SettingsGetter defines the contract to retrieve Argo CD Settings. @@ -114,6 +235,36 @@ func (s *DefaultSettingsGetter) Get() (*settings.ArgoCDSettings, error) { return s.settingsMgr.GetSettings() } +// ProjectGetter defines the contract to retrieve Argo CD Project. +type ProjectGetter interface { + Get(name string) (*v1alpha1.AppProject, error) + GetClusters(project string) ([]*v1alpha1.Cluster, error) +} + +// DefaultProjectGetter is the real ProjectGetter implementation. +type DefaultProjectGetter struct { + projLister applisters.AppProjectNamespaceLister + db db.ArgoDB +} + +// NewDefaultProjectGetter returns a new default project getter +func NewDefaultProjectGetter(lister applisters.AppProjectNamespaceLister, db db.ArgoDB) *DefaultProjectGetter { + return &DefaultProjectGetter{ + projLister: lister, + db: db, + } +} + +// Get will retrieve the live AppProject state. +func (p *DefaultProjectGetter) Get(name string) (*v1alpha1.AppProject, error) { + return p.projLister.Get(name) +} + +// GetClusters will retrieve the clusters configured by a project. +func (p *DefaultProjectGetter) GetClusters(project string) ([]*v1alpha1.Cluster, error) { + return p.db.GetProjectClusters(context.TODO(), project) +} + // ApplicationGetter defines the contract to retrieve the application resource. type ApplicationGetter interface { Get(ns, name string) (*v1alpha1.Application, error) @@ -121,23 +272,24 @@ type ApplicationGetter interface { // DefaultApplicationGetter is the real application getter implementation. type DefaultApplicationGetter struct { - svc applicationpkg.ApplicationServiceServer + appLister applisters.ApplicationLister } // NewDefaultApplicationGetter returns the default application getter. -func NewDefaultApplicationGetter(appSvc applicationpkg.ApplicationServiceServer) *DefaultApplicationGetter { +func NewDefaultApplicationGetter(al applisters.ApplicationLister) *DefaultApplicationGetter { return &DefaultApplicationGetter{ - svc: appSvc, + appLister: al, } } // Get will retrieve the application resorce for the given namespace and name. func (a *DefaultApplicationGetter) Get(ns, name string) (*v1alpha1.Application, error) { - query := &applicationpkg.ApplicationQuery{ - Name: pointer.String(name), - AppNamespace: pointer.String(ns), - } - return a.svc.Get(context.Background(), query) + return a.appLister.Applications(ns).Get(name) +} + +// RbacEnforcer defines the contract to enforce rbac rules +type RbacEnforcer interface { + EnforceErr(rvals ...interface{}) error } // Manager is the object that will be responsible for registering @@ -146,22 +298,91 @@ type Manager struct { log *log.Entry settings SettingsGetter application ApplicationGetter + 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. -func NewManager(sg SettingsGetter, ag ApplicationGetter, log *log.Entry) *Manager { +func NewManager(log *log.Entry, sg SettingsGetter, ag ApplicationGetter, pg ProjectGetter, rbac RbacEnforcer) *Manager { return &Manager{ log: log, settings: sg, application: ag, + project: pg, + rbac: rbac, } } -func parseAndValidateConfig(config string) (*ExtensionConfigs, error) { +// ExtensionRegistry is an in memory registry that contains contains all +// proxies for all extensions. The key is the extension name defined in +// the Argo CD configmap. +type ExtensionRegistry map[string]ProxyRegistry + +// ProxyRegistry is an in memory registry that contains all proxies for a +// given extension. Different extensions will have independent proxy registries. +// This is required to address the use case when one extension is configured with +// multiple backend services in different clusters. +type ProxyRegistry map[ProxyKey]*httputil.ReverseProxy + +// NewProxyRegistry will instantiate a new in memory registry for proxies. +func NewProxyRegistry() ProxyRegistry { + r := make(map[ProxyKey]*httputil.ReverseProxy) + return r +} + +// ProxyKey defines the struct used as a key in the proxy registry +// map (ProxyRegistry). +type ProxyKey struct { + extensionName string + clusterName string + clusterServer string +} + +// proxyKey will build the key to be used in the proxyByCluster +// map. +func proxyKey(extName, cName, cServer string) ProxyKey { + return ProxyKey{ + extensionName: extName, + clusterName: cName, + clusterServer: cServer, + } +} + +func parseAndValidateConfig(s *settings.ArgoCDSettings) (*ExtensionConfigs, error) { + if s.ExtensionConfig == "" { + return nil, fmt.Errorf("no extensions configurations found") + } + + extConfigMap := map[string]interface{}{} + err := yaml.Unmarshal([]byte(s.ExtensionConfig), &extConfigMap) + if err != nil { + return nil, fmt.Errorf("invalid extension config: %s", err) + } + + parsedExtConfig := settings.ReplaceMapSecrets(extConfigMap, s.Secrets) + parsedExtConfigBytes, err := yaml.Marshal(parsedExtConfig) + if err != nil { + return nil, fmt.Errorf("error marshaling parsed extension config: %s", err) + } + configs := ExtensionConfigs{} - err := yaml.Unmarshal([]byte(config), &configs) + err = yaml.Unmarshal(parsedExtConfigBytes, &configs) if err != nil { - return nil, fmt.Errorf("invalid yaml: %s", err) + return nil, fmt.Errorf("invalid parsed extension config: %s", err) } err = validateConfigs(&configs) if err != nil { @@ -172,6 +393,7 @@ func parseAndValidateConfig(config string) (*ExtensionConfigs, error) { func validateConfigs(configs *ExtensionConfigs) error { nameSafeRegex := regexp.MustCompile(`^[A-Za-z0-9-_]+$`) + exts := make(map[string]struct{}) for _, ext := range configs.Extensions { if ext.Name == "" { return fmt.Errorf("extensions.name must be configured") @@ -179,28 +401,63 @@ func validateConfigs(configs *ExtensionConfigs) error { if !nameSafeRegex.MatchString(ext.Name) { return fmt.Errorf("invalid extensions.name: only alphanumeric characters, hyphens, and underscores are allowed") } + if _, found := exts[ext.Name]; found { + return fmt.Errorf("duplicated extension found in the configs for %q", ext.Name) + } + exts[ext.Name] = struct{}{} svcTotal := len(ext.Backend.Services) + if svcTotal == 0 { + return fmt.Errorf("no backend service configured for extension %s", ext.Name) + } for _, svc := range ext.Backend.Services { if svc.URL == "" { return fmt.Errorf("extensions.backend.services.url must be configured") } - if svcTotal > 1 && svc.Cluster == "" { + if svcTotal > 1 && svc.Cluster == nil { return fmt.Errorf("extensions.backend.services.cluster must be configured when defining more than one service per extension") } + if svc.Cluster != nil { + if svc.Cluster.Name == "" && svc.Cluster.Server == "" { + return fmt.Errorf("cluster.name or cluster.server must be defined when cluster is provided in the configuration") + } + } + if len(svc.Headers) > 0 { + for _, header := range svc.Headers { + if header.Name == "" { + return fmt.Errorf("header.name must be defined when providing service headers in the configuration") + } + if header.Value == "" { + return fmt.Errorf("header.value must be defined when providing service headers in the configuration") + } + } + } } } return nil } // NewProxy will instantiate a new reverse proxy based on the provided -// targetURL and config. -func NewProxy(targetURL string, config ProxyConfig) (*httputil.ReverseProxy, error) { +// 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 { return nil, fmt.Errorf("failed to parse proxy URL: %s", err) } - proxy := httputil.NewSingleHostReverseProxy(url) - proxy.Transport = newTransport(config) + proxy := &httputil.ReverseProxy{ + Transport: newTransport(config), + Director: func(req *http.Request) { + req.Host = url.Host + req.URL.Scheme = url.Scheme + req.URL.Host = url.Host + req.Header.Set("Host", url.Host) + req.Header.Del("Authorization") + req.Header.Del("Cookie") + for _, header := range headers { + req.Header.Set(header.Name, header.Value) + } + }, + } return proxy, nil } @@ -235,123 +492,247 @@ func applyProxyConfigDefaults(c *ProxyConfig) { } } -// RegisterHandlers will retrieve all configured extensions -// and register the respective http handlers in the given -// router. -func (m *Manager) RegisterHandlers(r *mux.Router) error { - m.log.Info("Registering extension handlers...") - config, err := m.settings.Get() +// RegisterExtensions will retrieve all extensions configurations +// and update the extension registry. +func (m *Manager) RegisterExtensions() error { + settings, err := m.settings.Get() if err != nil { return fmt.Errorf("error getting settings: %s", err) } - - if config.ExtensionConfig == "" { - return fmt.Errorf("No extensions configurations found") + if settings.ExtensionConfig == "" { + m.log.Infof("No extensions configured.") + return nil } - - extConfigs, err := parseAndValidateConfig(config.ExtensionConfig) + err = m.UpdateExtensionRegistry(settings) if err != nil { - return fmt.Errorf("error parsing extension config: %s", err) + return fmt.Errorf("error updating extension registry: %s", err) } - return m.registerExtensions(r, extConfigs) + return nil } -// registerExtensions will iterate over the given extConfigs and register -// http handlers for every extension. It also registers a list extensions -// handler under the "/extensions/" endpoint. -func (m *Manager) registerExtensions(r *mux.Router, extConfigs *ExtensionConfigs) error { - extRouter := r.PathPrefix(fmt.Sprintf("%s/", URLPrefix)).Subrouter() +// UpdateExtensionRegistry will first parse and validate the extensions +// configurations from the given settings. If no errors are found, it will +// iterate over the given configurations building a new extension registry. +// At the end, it will update the manager with the newly created registry. +func (m *Manager) UpdateExtensionRegistry(s *settings.ArgoCDSettings) error { + extConfigs, err := parseAndValidateConfig(s) + if err != nil { + return fmt.Errorf("error parsing extension config: %s", err) + } + extReg := make(map[string]ProxyRegistry) for _, ext := range extConfigs.Extensions { - proxyByCluster := make(map[string]*httputil.ReverseProxy) + proxyReg := NewProxyRegistry() + singleBackend := len(ext.Backend.Services) == 1 for _, service := range ext.Backend.Services { - proxy, err := NewProxy(service.URL, ext.Backend.ProxyConfig) + proxy, err := NewProxy(service.URL, service.Headers, ext.Backend.ProxyConfig) if err != nil { return fmt.Errorf("error creating proxy: %s", err) } - proxyByCluster[service.Cluster] = proxy + err = appendProxy(proxyReg, ext.Name, service, proxy, singleBackend) + if err != nil { + return fmt.Errorf("error appending proxy: %s", err) + } + } + extReg[ext.Name] = proxyReg + } + m.registry = extReg + return nil +} + +// appendProxy will append the given proxy in the given registry. Will use +// the provided extName and service to determine the map key. The key must +// be unique in the map. If the map already has the key and error is returned. +func appendProxy(registry ProxyRegistry, + extName string, + service ServiceConfig, + proxy *httputil.ReverseProxy, + singleBackend bool) error { + + if singleBackend { + key := proxyKey(extName, "", "") + if _, exist := registry[key]; exist { + return fmt.Errorf("duplicated proxy configuration found for extension key %q", key) + } + registry[key] = proxy + return nil + } + + // This is the case where there are more than one backend configured + // for this extension. In this case we need to add the provided cluster + // configurations for proper correlation to find which proxy to use + // while handling requests. + if service.Cluster.Name != "" { + key := proxyKey(extName, service.Cluster.Name, "") + if _, exist := registry[key]; exist { + return fmt.Errorf("duplicated proxy configuration found for extension key %q", key) + } + registry[key] = proxy + } + if service.Cluster.Server != "" { + key := proxyKey(extName, "", service.Cluster.Server) + if _, exist := registry[key]; exist { + return fmt.Errorf("duplicated proxy configuration found for extension key %q", key) } - m.log.Infof("Registering handler for %s/%s...", URLPrefix, ext.Name) - extRouter.PathPrefix(fmt.Sprintf("/%s/", ext.Name)). - HandlerFunc(m.CallExtension(ext.Name, proxyByCluster)) + registry[key] = proxy } return nil } +// authorize will enforce rbac rules are satified for the given RequestResources. +// The following validations are executed: +// - enforce the subject has permission to read application/project provided +// in HeaderArgoCDApplicationName and HeaderArgoCDProjectName. +// - enforce the subject has permission to invoke the extension identified by +// extName. +// - enforce that the project has permission to access the destination cluster. +// +// If all validations are satified it will return the Application resource +func (m *Manager) authorize(ctx context.Context, rr *RequestResources, extName string) (*v1alpha1.Application, error) { + if m.rbac == nil { + return nil, fmt.Errorf("rbac enforcer not set in extension manager") + } + appRBACName := security.RBACName(rr.ApplicationNamespace, rr.ProjectName, rr.ApplicationNamespace, rr.ApplicationName) + if err := m.rbac.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, appRBACName); err != nil { + return nil, fmt.Errorf("application authorization error: %s", err) + } + + if err := m.rbac.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceExtensions, rbacpolicy.ActionInvoke, extName); err != nil { + return nil, fmt.Errorf("unauthorized to invoke extension %q: %s", extName, err) + } + + // just retrieve the app after checking if subject has access to it + app, err := m.application.Get(rr.ApplicationNamespace, rr.ApplicationName) + if err != nil { + return nil, fmt.Errorf("error getting application: %s", err) + } + if app == nil { + return nil, fmt.Errorf("invalid Application provided in the %q header", HeaderArgoCDApplicationName) + } + + if app.Spec.GetProject() != rr.ProjectName { + return nil, fmt.Errorf("project mismatch provided in the %q header", HeaderArgoCDProjectName) + } + + proj, err := m.project.Get(app.Spec.GetProject()) + if err != nil { + return nil, fmt.Errorf("error getting project: %s", err) + } + if proj == nil { + return nil, fmt.Errorf("invalid project provided in the %q header", HeaderArgoCDProjectName) + } + permitted, err := proj.IsDestinationPermitted(app.Spec.Destination, m.project.GetClusters) + if err != nil { + return nil, fmt.Errorf("error validating project destinations: %s", err) + } + if !permitted { + return nil, fmt.Errorf("the provided project is not allowed to access the cluster configured in the Application destination") + } + + return app, nil +} + +// findProxy will search the given registry to find the correct proxy to use +// based on the given extName and dest. +func findProxy(registry ProxyRegistry, extName string, dest v1alpha1.ApplicationDestination) (*httputil.ReverseProxy, error) { + + // First try to find the proxy in the registry just by the extension name. + // This is the simple case for extensions with only one backend service. + key := proxyKey(extName, "", "") + if proxy, found := registry[key]; found { + return proxy, nil + } + + // If extension has multiple backend services configured, the correct proxy + // needs to be searched by the ApplicationDestination. + key = proxyKey(extName, dest.Name, dest.Server) + if proxy, found := registry[key]; found { + return proxy, nil + } + + return nil, fmt.Errorf("no proxy found for extension %q", extName) +} + +// ProxyRegistry returns the proxy registry associated for the given +// extension name. +func (m *Manager) ProxyRegistry(name string) (ProxyRegistry, bool) { + pReg, found := m.registry[name] + return pReg, found +} + // CallExtension returns a handler func responsible for forwarding requests to the // extension service. The request will be sanitized by removing sensitive headers. -func (m *Manager) CallExtension(extName string, proxyByCluster map[string]*httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) { +func (m *Manager) CallExtension() func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { - sanitizeRequest(r, extName) - if len(proxyByCluster) == 1 { - for _, proxy := range proxyByCluster { - proxy.ServeHTTP(w, r) - return - } - } - appHeader := r.Header.Get(HeaderArgoCDApplicationName) - if appHeader == "" { - msg := fmt.Sprintf("Header %q must be provided", HeaderArgoCDApplicationName) - m.writeErrorResponse(http.StatusBadRequest, msg, w) + segments := strings.Split(strings.TrimPrefix(r.URL.Path, "/"), "/") + if segments[0] != "extensions" { + http.Error(w, fmt.Sprintf("Invalid URL: first segment must be %s", URLPrefix), http.StatusBadRequest) return } - appNamespace, appName, err := getAppName(appHeader) - if err != nil { - msg := fmt.Sprintf("Error getting application name: %s", err) - m.writeErrorResponse(http.StatusBadRequest, msg, w) + extName := segments[1] + if extName == "" { + http.Error(w, "Invalid URL: extension name must be provided", http.StatusBadRequest) return } - app, err := m.application.Get(appNamespace, appName) + extName = strings.ReplaceAll(extName, "\n", "") + extName = strings.ReplaceAll(extName, "\r", "") + reqResources, err := ValidateHeaders(r) if err != nil { - msg := fmt.Sprintf("Error getting application: %s", err) - m.writeErrorResponse(http.StatusBadRequest, msg, w) + http.Error(w, fmt.Sprintf("Invalid headers: %s", err), http.StatusBadRequest) return } - if app == nil { - msg := fmt.Sprintf("Invalid Application: %s", appHeader) - m.writeErrorResponse(http.StatusBadRequest, msg, w) + app, err := m.authorize(r.Context(), reqResources, extName) + if err != nil { + m.log.Infof("unauthorized extension request: %s", err) + http.Error(w, "Unauthorized extension request", http.StatusUnauthorized) return } - clusterName := app.Spec.Destination.Name - if clusterName == "" { - clusterName = app.Spec.Destination.Server - } - proxy, ok := proxyByCluster[clusterName] + proxyRegistry, ok := m.ProxyRegistry(extName) if !ok { - msg := fmt.Sprintf("No extension configured for cluster %q", clusterName) - m.writeErrorResponse(http.StatusBadRequest, msg, w) + m.log.Warnf("proxy extension warning: attempt to call unregistered extension: %s", extName) + http.Error(w, "Extension not found", http.StatusNotFound) + return + } + proxy, err := findProxy(proxyRegistry, extName, app.Spec.Destination) + if err != nil { + m.log.Errorf("findProxy error: %s", err) + http.Error(w, "invalid extension", http.StatusBadRequest) return } - proxy.ServeHTTP(w, r) - } -} -func getAppName(appHeader string) (string, string, error) { - parts := strings.Split(appHeader, "/") - if len(parts) != 2 { - return "", "", fmt.Errorf("invalid header value %q: expected format: /", appHeader) + prepareRequest(r, extName, app) + m.log.Debugf("proxing request for extension %q", extName) + // 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) } - return parts[0], parts[1], nil } -func sanitizeRequest(r *http.Request, extName string) { - r.URL.Path = strings.TrimPrefix(r.URL.String(), fmt.Sprintf("%s/%s", URLPrefix, extName)) +func registerMetrics(extName string, metrics httpsnoop.Metrics, extensionMetricsRegistry ExtensionMetricsRegistry) { + if extensionMetricsRegistry != nil { + extensionMetricsRegistry.IncExtensionRequestCounter(extName, metrics.Code) + extensionMetricsRegistry.ObserveExtensionRequestDuration(extName, metrics.Duration) + } } -func (m *Manager) writeErrorResponse(status int, message string, w http.ResponseWriter) { - w.WriteHeader(status) - w.Header().Set("Content-Type", "application/json") - resp := make(map[string]string) - resp["status"] = http.StatusText(status) - resp["message"] = message - jsonResp, err := json.Marshal(resp) - if err != nil { - m.log.Errorf("Error marshaling response for extension: %s", err) - return +// 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 != "" { + r.Header.Set(HeaderArgoCDTargetClusterName, app.Spec.Destination.Name) } - _, err = w.Write(jsonResp) - if err != nil { - m.log.Errorf("Error writing response for extension: %s", err) - return + if app.Spec.Destination.Server != "" { + 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 a6fa7b5d6cf8f..ff287dde80424 100644 --- a/server/extension/extension_test.go +++ b/server/extension/extension_test.go @@ -2,26 +2,144 @@ package extension_test import ( "context" + "errors" "fmt" "io" "net/http" "net/http/httptest" "strings" + "sync" "testing" - "github.com/gorilla/mux" "github.com/sirupsen/logrus/hooks/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/server/extension" "github.com/argoproj/argo-cd/v2/server/extension/mocks" + "github.com/argoproj/argo-cd/v2/server/rbacpolicy" "github.com/argoproj/argo-cd/v2/util/settings" ) -func TestRegisterHandlers(t *testing.T) { +func TestValidateHeaders(t *testing.T) { + t.Run("will build RequestResources successfully", func(t *testing.T) { + // given + r, err := http.NewRequest("Get", "http://null", nil) + if err != nil { + t.Fatalf("error initializing request: %s", err) + } + r.Header.Add(extension.HeaderArgoCDApplicationName, "namespace:app-name") + r.Header.Add(extension.HeaderArgoCDProjectName, "project-name") + + // when + rr, err := extension.ValidateHeaders(r) + + // then + require.NoError(t, err) + assert.NotNil(t, rr) + assert.Equal(t, "namespace", rr.ApplicationNamespace) + assert.Equal(t, "app-name", rr.ApplicationName) + assert.Equal(t, "project-name", rr.ProjectName) + }) + t.Run("will return error if application is malformatted", func(t *testing.T) { + // given + r, err := http.NewRequest("Get", "http://null", nil) + if err != nil { + t.Fatalf("error initializing request: %s", err) + } + r.Header.Add(extension.HeaderArgoCDApplicationName, "no-namespace") + + // when + rr, err := extension.ValidateHeaders(r) + + // then + assert.Error(t, err) + assert.Nil(t, rr) + }) + t.Run("will return error if application header is missing", func(t *testing.T) { + // given + r, err := http.NewRequest("Get", "http://null", nil) + if err != nil { + t.Fatalf("error initializing request: %s", err) + } + r.Header.Add(extension.HeaderArgoCDProjectName, "project-name") + + // when + rr, err := extension.ValidateHeaders(r) + + // then + assert.Error(t, err) + assert.Nil(t, rr) + }) + t.Run("will return error if project header is missing", func(t *testing.T) { + // given + r, err := http.NewRequest("Get", "http://null", nil) + if err != nil { + t.Fatalf("error initializing request: %s", err) + } + r.Header.Add(extension.HeaderArgoCDApplicationName, "namespace:app-name") + + // when + rr, err := extension.ValidateHeaders(r) + + // then + assert.Error(t, err) + assert.Nil(t, rr) + }) + t.Run("will return error if invalid namespace", func(t *testing.T) { + // given + r, err := http.NewRequest("Get", "http://null", nil) + if err != nil { + t.Fatalf("error initializing request: %s", err) + } + r.Header.Add(extension.HeaderArgoCDApplicationName, "bad%namespace:app-name") + r.Header.Add(extension.HeaderArgoCDProjectName, "project-name") + + // when + rr, err := extension.ValidateHeaders(r) + + // then + assert.Error(t, err) + assert.Nil(t, rr) + }) + t.Run("will return error if invalid app name", func(t *testing.T) { + // given + r, err := http.NewRequest("Get", "http://null", nil) + if err != nil { + t.Fatalf("error initializing request: %s", err) + } + r.Header.Add(extension.HeaderArgoCDApplicationName, "namespace:bad@app") + r.Header.Add(extension.HeaderArgoCDProjectName, "project-name") + + // when + rr, err := extension.ValidateHeaders(r) + + // then + assert.Error(t, err) + assert.Nil(t, rr) + }) + t.Run("will return error if invalid project name", func(t *testing.T) { + // given + r, err := http.NewRequest("Get", "http://null", nil) + if err != nil { + t.Fatalf("error initializing request: %s", err) + } + r.Header.Add(extension.HeaderArgoCDApplicationName, "namespace:app") + r.Header.Add(extension.HeaderArgoCDProjectName, "bad^project") + + // when + rr, err := extension.ValidateHeaders(r) + + // then + assert.Error(t, err) + assert.Nil(t, rr) + }) +} + +func TestRegisterExtensions(t *testing.T) { type fixture struct { settingsGetterMock *mocks.SettingsGetter manager *extension.Manager @@ -32,56 +150,53 @@ func TestRegisterHandlers(t *testing.T) { logger, _ := test.NewNullLogger() logEntry := logger.WithContext(context.Background()) - m := extension.NewManager(settMock, nil, logEntry) + m := extension.NewManager(logEntry, settMock, nil, nil, nil) return &fixture{ settingsGetterMock: settMock, manager: m, } } - t.Run("will register handlers successfully", func(t *testing.T) { + t.Run("will register extensions successfully", func(t *testing.T) { // given + t.Parallel() f := setup() - router := mux.NewRouter() settings := &settings.ArgoCDSettings{ ExtensionConfig: getExtensionConfigString(), } f.settingsGetterMock.On("Get", mock.Anything).Return(settings, nil) - expectedRegexRoutes := []string{ - "^/extensions/", - "^/extensions/external-backend/", - "^/extensions/some-backend/", - "^/extensions/$"} + expectedProxyRegistries := []string{ + "external-backend", + "some-backend"} // when - err := f.manager.RegisterHandlers(router) + err := f.manager.RegisterExtensions() // then require.NoError(t, err) - walkFn := func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { - pathRegex, err := route.GetPathRegexp() - require.NoError(t, err) - assert.Contains(t, expectedRegexRoutes, pathRegex) - return nil + for _, expectedProxyRegistry := range expectedProxyRegistries { + proxyRegistry, found := f.manager.ProxyRegistry(expectedProxyRegistry) + assert.True(t, found) + assert.NotNil(t, proxyRegistry) } - err = router.Walk(walkFn) - assert.NoError(t, err) + }) t.Run("will return error if extension config is invalid", func(t *testing.T) { // given + t.Parallel() type testCase struct { name string configYaml string } cases := []testCase{ - { - name: "no config", - configYaml: "", - }, { name: "no name", configYaml: getExtensionConfigNoName(), }, + { + name: "no service", + configYaml: getExtensionConfigNoService(), + }, { name: "no URL", configYaml: getExtensionConfigNoURL(), @@ -90,6 +205,14 @@ func TestRegisterHandlers(t *testing.T) { name: "invalid name", configYaml: getExtensionConfigInvalidName(), }, + { + name: "no header name", + configYaml: getExtensionConfigNoHeaderName(), + }, + { + name: "no header value", + configYaml: getExtensionConfigNoHeaderValue(), + }, } // when @@ -97,159 +220,291 @@ func TestRegisterHandlers(t *testing.T) { tc := tc t.Run(tc.name, func(t *testing.T) { // given + t.Parallel() f := setup() - router := mux.NewRouter() settings := &settings.ArgoCDSettings{ ExtensionConfig: tc.configYaml, } f.settingsGetterMock.On("Get", mock.Anything).Return(settings, nil) // when - err := f.manager.RegisterHandlers(router) + 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)) }) } }) } -func TestExtensionsHandlers(t *testing.T) { +func TestCallExtension(t *testing.T) { type fixture struct { - router *mux.Router + mux *http.ServeMux appGetterMock *mocks.ApplicationGetter settingsGetterMock *mocks.SettingsGetter + rbacMock *mocks.RbacEnforcer + projMock *mocks.ProjectGetter + metricsMock *mocks.ExtensionMetricsRegistry manager *extension.Manager } + defaultProjectName := "project-name" setup := func() *fixture { appMock := &mocks.ApplicationGetter{} settMock := &mocks.SettingsGetter{} + rbacMock := &mocks.RbacEnforcer{} + projMock := &mocks.ProjectGetter{} + metricsMock := &mocks.ExtensionMetricsRegistry{} logger, _ := test.NewNullLogger() logEntry := logger.WithContext(context.Background()) - m := extension.NewManager(settMock, appMock, logEntry) + m := extension.NewManager(logEntry, settMock, appMock, projMock, rbacMock) + m.AddMetricsRegistry(metricsMock) - router := mux.NewRouter() + mux := http.NewServeMux() + extHandler := http.HandlerFunc(m.CallExtension()) + mux.Handle(fmt.Sprintf("%s/", extension.URLPrefix), extHandler) return &fixture{ - router: router, + mux: mux, appGetterMock: appMock, settingsGetterMock: settMock, + rbacMock: rbacMock, + projMock: projMock, + metricsMock: metricsMock, manager: m, } } + getApp := func(destName, destServer, projName string) *v1alpha1.Application { + return &v1alpha1.Application{ + TypeMeta: v1.TypeMeta{}, + ObjectMeta: v1.ObjectMeta{}, + Spec: v1alpha1.ApplicationSpec{ + Destination: v1alpha1.ApplicationDestination{ + Name: destName, + Server: destServer, + }, + Project: projName, + }, + Status: v1alpha1.ApplicationStatus{ + Resources: []v1alpha1.ResourceStatus{ + { + Group: "apps", + Version: "v1", + Kind: "Pod", + Namespace: "default", + Name: "some-pod", + }, + }, + }, + } + } + + getProjectWithDestinations := func(prjName string, destNames []string, destURLs []string) *v1alpha1.AppProject { + destinations := []v1alpha1.ApplicationDestination{} + for _, destName := range destNames { + destination := v1alpha1.ApplicationDestination{ + Name: destName, + } + destinations = append(destinations, destination) + } + for _, destURL := range destURLs { + destination := v1alpha1.ApplicationDestination{ + Server: destURL, + } + destinations = append(destinations, destination) + } + return &v1alpha1.AppProject{ + ObjectMeta: v1.ObjectMeta{ + Name: prjName, + }, + Spec: v1alpha1.AppProjectSpec{ + Destinations: destinations, + }, + } + } + + withProject := func(prj *v1alpha1.AppProject, f *fixture) { + 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 + if !allowApp { + appAccessError = errors.New("no app permission") + } + if !allowExt { + extAccessError = errors.New("no extension permission") + } + f.rbacMock.On("EnforceErr", mock.Anything, rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, mock.Anything).Return(appAccessError) + f.rbacMock.On("EnforceErr", mock.Anything, rbacpolicy.ResourceExtensions, rbacpolicy.ActionInvoke, mock.Anything).Return(extAccessError) + } + withExtensionConfig := func(configYaml string, f *fixture) { + secrets := make(map[string]string) + secrets["extension.auth.header"] = "Bearer some-bearer-token" + secrets["extension.auth.header2"] = "Bearer another-bearer-token" + settings := &settings.ArgoCDSettings{ ExtensionConfig: configYaml, + Secrets: secrets, } f.settingsGetterMock.On("Get", mock.Anything).Return(settings, nil) } startTestServer := func(t *testing.T, f *fixture) *httptest.Server { - err := f.manager.RegisterHandlers(f.router) + t.Helper() + err := f.manager.RegisterExtensions() if err != nil { t.Fatalf("error starting test server: %s", err) } - return httptest.NewServer(f.router) + return httptest.NewServer(f.mux) } startBackendTestSrv := func(response string) *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + for k, v := range r.Header { + w.Header().Add(k, strings.Join(v, ",")) + } fmt.Fprintln(w, response) })) } - t.Run("proxy will return 404 if no extension endpoint is registered", func(t *testing.T) { - // given - f := setup() - withExtensionConfig(getExtensionConfigString(), f) - ts := startTestServer(t, f) - defer ts.Close() - nonRegisteredEndpoint := "non-registered" - - // when - resp, err := http.Get(fmt.Sprintf("%s/extensions/%s/", ts.URL, nonRegisteredEndpoint)) + newExtensionRequest := func(t *testing.T, method, url string) *http.Request { + t.Helper() + r, err := http.NewRequest(method, url, nil) + if err != nil { + t.Fatalf("error initializing request: %s", err) + } + r.Header.Add(extension.HeaderArgoCDApplicationName, "namespace:app-name") + r.Header.Add(extension.HeaderArgoCDProjectName, defaultProjectName) + return r + } - // then - require.NoError(t, err) - require.NotNil(t, resp) - assert.Equal(t, http.StatusNotFound, resp.StatusCode) - }) t.Run("will call extension backend successfully", func(t *testing.T) { // given + t.Parallel() f := setup() backendResponse := "some data" backendEndpoint := "some-backend" + clusterName := "clusterName" + clusterURL := "clusterURL" backendSrv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + for k, v := range r.Header { + w.Header().Add(k, strings.Join(v, ",")) + } fmt.Fprintln(w, backendResponse) })) defer backendSrv.Close() + withRbac(f, true, true) withExtensionConfig(getExtensionConfig(backendEndpoint, backendSrv.URL), f) ts := startTestServer(t, f) defer ts.Close() + r := newExtensionRequest(t, "Get", fmt.Sprintf("%s/extensions/%s/", ts.URL, backendEndpoint)) + app := getApp(clusterName, clusterURL, defaultProjectName) + 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.Get(fmt.Sprintf("%s/extensions/%s/", ts.URL, backendEndpoint)) + resp, err := http.DefaultClient.Do(r) // then require.NoError(t, err) require.NotNil(t, resp) - require.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, http.StatusOK, resp.StatusCode) body, err := io.ReadAll(resp.Body) require.NoError(t, err) actual := strings.TrimSuffix(string(body), "\n") 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 + t.Parallel() + 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) + + ts := startTestServer(t, f) + defer ts.Close() + nonRegistered := "non-registered" + r := newExtensionRequest(t, "Get", fmt.Sprintf("%s/extensions/%s/", ts.URL, nonRegistered)) + + // when + resp, err := http.DefaultClient.Do(r) + + // then + require.NoError(t, err) + require.NotNil(t, resp) + assert.Equal(t, http.StatusNotFound, resp.StatusCode) }) t.Run("will route requests with 2 backends for the same extension successfully", func(t *testing.T) { // given + t.Parallel() f := setup() extName := "some-extension" response1 := "response backend 1" - cluster1 := "cluster1" + cluster1Name := "cluster1" beSrv1 := startBackendTestSrv(response1) defer beSrv1.Close() response2 := "response backend 2" - cluster2 := "cluster2" + cluster2URL := "cluster2" beSrv2 := startBackendTestSrv(response2) defer beSrv2.Close() - withExtensionConfig(getExtensionConfigWith2Backends(extName, beSrv1.URL, cluster1, beSrv2.URL, cluster2), f) - ts := startTestServer(t, f) - defer ts.Close() + f.appGetterMock.On("Get", "ns1", "app1").Return(getApp(cluster1Name, "", defaultProjectName), nil) + f.appGetterMock.On("Get", "ns2", "app2").Return(getApp("", cluster2URL, defaultProjectName), nil) - app1 := &v1alpha1.Application{ - Spec: v1alpha1.ApplicationSpec{ - Destination: v1alpha1.ApplicationDestination{ - Server: beSrv1.URL, - Name: cluster1, - }, - }, - } - f.appGetterMock.On("Get", "ns1", "app1").Return(app1, nil) + 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) - app2 := &v1alpha1.Application{ - Spec: v1alpha1.ApplicationSpec{ - Destination: v1alpha1.ApplicationDestination{ - Server: beSrv2.URL, - Name: cluster2, - }, - }, - } - f.appGetterMock.On("Get", "ns2", "app2").Return(app2, nil) + ts := startTestServer(t, f) + defer ts.Close() url := fmt.Sprintf("%s/extensions/%s/", ts.URL, extName) - req, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - t.Fatalf("error creating request: %s", err) - } + req := newExtensionRequest(t, http.MethodGet, url) + req.Header.Del(extension.HeaderArgoCDApplicationName) + req1 := req.Clone(context.Background()) - req1.Header.Add(extension.HeaderArgoCDApplicationName, "ns1/app1") + req1.Header.Add(extension.HeaderArgoCDApplicationName, "ns1:app1") req2 := req.Clone(context.Background()) - req2.Header.Add(extension.HeaderArgoCDApplicationName, "ns2/app2") + req2.Header.Add(extension.HeaderArgoCDApplicationName, "ns2:app2") // when resp1, err := http.DefaultClient.Do(req1) @@ -259,18 +514,204 @@ func TestExtensionsHandlers(t *testing.T) { // then require.NotNil(t, resp1) - require.Equal(t, http.StatusOK, resp1.StatusCode) + assert.Equal(t, http.StatusOK, resp1.StatusCode) body, err := io.ReadAll(resp1.Body) require.NoError(t, err) actual := strings.TrimSuffix(string(body), "\n") assert.Equal(t, response1, actual) + assert.Equal(t, "Bearer some-bearer-token", resp1.Header.Get("Authorization")) require.NotNil(t, resp2) - require.Equal(t, http.StatusOK, resp2.StatusCode) + assert.Equal(t, http.StatusOK, resp2.StatusCode) body, err = io.ReadAll(resp2.Body) require.NoError(t, err) actual = strings.TrimSuffix(string(body), "\n") assert.Equal(t, response2, actual) + assert.Equal(t, "Bearer another-bearer-token", resp2.Header.Get("Authorization")) + }) + t.Run("will return 401 if sub has no access to get application", func(t *testing.T) { + // given + t.Parallel() + f := setup() + allowApp := false + allowExtension := true + 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)) + f.appGetterMock.On("Get", mock.Anything, mock.Anything).Return(getApp("", "", defaultProjectName), nil) + + // when + resp, err := http.DefaultClient.Do(r) + + // then + require.NoError(t, err) + require.NotNil(t, resp) + assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) + }) + t.Run("will return 401 if sub has no access to invoke extension", func(t *testing.T) { + // given + t.Parallel() + f := setup() + allowApp := true + allowExtension := false + 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)) + f.appGetterMock.On("Get", mock.Anything, mock.Anything).Return(getApp("", "", defaultProjectName), nil) + + // when + resp, err := http.DefaultClient.Do(r) + + // then + require.NoError(t, err) + require.NotNil(t, resp) + assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) + }) + t.Run("will return 401 if project has no access to target cluster", func(t *testing.T) { + // given + t.Parallel() + f := setup() + allowApp := true + allowExtension := true + extName := "some-extension" + 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)) + f.appGetterMock.On("Get", mock.Anything, mock.Anything).Return(getApp("", "", defaultProjectName), nil) + proj := getProjectWithDestinations("project-name", nil, noCluster) + withProject(proj, f) + + // when + resp, err := http.DefaultClient.Do(r) + + // then + require.NoError(t, err) + require.NotNil(t, resp) + assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) + }) + t.Run("will return 401 if project in application does not exist", func(t *testing.T) { + // given + t.Parallel() + f := setup() + allowApp := true + allowExtension := true + 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)) + f.appGetterMock.On("Get", mock.Anything, mock.Anything).Return(getApp("", "", defaultProjectName), nil) + f.projMock.On("Get", defaultProjectName).Return(nil, nil) + + // when + resp, err := http.DefaultClient.Do(r) + + // then + require.NoError(t, err) + require.NotNil(t, resp) + assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) + }) + t.Run("will return 401 if project in application does not match with header", func(t *testing.T) { + // given + t.Parallel() + f := setup() + allowApp := true + allowExtension := true + extName := "some-extension" + 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)) + f.appGetterMock.On("Get", mock.Anything, mock.Anything).Return(getApp("", "", differentProject), nil) + + // when + resp, err := http.DefaultClient.Do(r) + + // then + require.NoError(t, err) + require.NotNil(t, resp) + assert.Equal(t, http.StatusUnauthorized, resp.StatusCode) + }) + t.Run("will return 400 if application defines name and server destination", func(t *testing.T) { + // This test is to validate a security risk with malicious application + // trying to gain access to execute extensions in clusters it doesn't + // have access. + + // given + t.Parallel() + f := setup() + extName := "some-extension" + maliciousName := "srv1" + destinationServer := "some-valid-server" + + f.appGetterMock.On("Get", "ns1", "app1").Return(getApp(maliciousName, destinationServer, defaultProjectName), nil) + + 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() + + url := fmt.Sprintf("%s/extensions/%s/", ts.URL, extName) + req := newExtensionRequest(t, http.MethodGet, url) + req.Header.Del(extension.HeaderArgoCDApplicationName) + req1 := req.Clone(context.Background()) + req1.Header.Add(extension.HeaderArgoCDApplicationName, "ns1:app1") + + // when + resp1, err := http.DefaultClient.Do(req1) + require.NoError(t, err) + + // then + require.NotNil(t, resp1) + assert.Equal(t, http.StatusBadRequest, resp1.StatusCode) + body, err := io.ReadAll(resp1.Body) + require.NoError(t, err) + actual := strings.TrimSuffix(string(body), "\n") + assert.Equal(t, "invalid extension", actual) + }) + t.Run("will return 400 if no extension name is provided", func(t *testing.T) { + // given + t.Parallel() + f := setup() + allowApp := true + allowExtension := true + extName := "some-extension" + 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)) + f.appGetterMock.On("Get", mock.Anything, mock.Anything).Return(getApp("", "", differentProject), nil) + + // when + resp, err := http.DefaultClient.Do(r) + + // then + require.NoError(t, err) + require.NotNil(t, resp) + assert.Equal(t, http.StatusBadRequest, resp.StatusCode) }) } @@ -281,22 +722,36 @@ extensions: backend: services: - url: %s + headers: + - name: Authorization + value: '$extension.auth.header' ` return fmt.Sprintf(cfg, name, url) } -func getExtensionConfigWith2Backends(name, url1, clus1, url2, clus2 string) string { +func getExtensionConfigWith2Backends(name, url1, clusName, url2, clusURL string) string { cfg := ` extensions: - name: %s backend: services: - url: %s - cluster: %s + headers: + - name: Authorization + value: '$extension.auth.header' + cluster: + name: %s - url: %s - cluster: %s + headers: + - name: Authorization + value: '$extension.auth.header2' + cluster: + server: %s ` - return fmt.Sprintf(cfg, name, url1, clus1, url2, clus2) + // second extension is configured with the cluster url rather + // than the cluster name so we can validate that both use-cases + // are working + return fmt.Sprintf(cfg, name, url1, clusName, url2, clusURL) } func getExtensionConfigString() string { @@ -304,8 +759,15 @@ func getExtensionConfigString() string { extensions: - name: external-backend backend: + connectionTimeout: 10s + keepAlive: 11s + idleConnectionTimeout: 12s + maxIdleConnections: 30 services: - url: https://httpbin.org + headers: + - name: some-header + value: '$some.secret.ref' - name: some-backend backend: services: @@ -313,6 +775,13 @@ extensions: ` } +func getExtensionConfigNoService() string { + return ` +extensions: +- backend: + connectionTimeout: 2s +` +} func getExtensionConfigNoName() string { return ` extensions: @@ -340,3 +809,27 @@ extensions: - cluster: some-cluster ` } + +func getExtensionConfigNoHeaderName() string { + return ` +extensions: +- name: some-extension + backend: + services: + - url: https://httpbin.org + headers: + - value: '$some.secret.key' +` +} + +func getExtensionConfigNoHeaderValue() string { + return ` +extensions: +- name: some-extension + backend: + services: + - url: https://httpbin.org + headers: + - name: some-header-name +` +} 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/extension/mocks/ProjectGetter.go b/server/extension/mocks/ProjectGetter.go new file mode 100644 index 0000000000000..d70b0c70ccfc6 --- /dev/null +++ b/server/extension/mocks/ProjectGetter.go @@ -0,0 +1,74 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import ( + v1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + mock "github.com/stretchr/testify/mock" +) + +// ProjectGetter is an autogenerated mock type for the ProjectGetter type +type ProjectGetter struct { + mock.Mock +} + +// Get provides a mock function with given fields: name +func (_m *ProjectGetter) Get(name string) (*v1alpha1.AppProject, error) { + ret := _m.Called(name) + + var r0 *v1alpha1.AppProject + if rf, ok := ret.Get(0).(func(string) *v1alpha1.AppProject); ok { + r0 = rf(name) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*v1alpha1.AppProject) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(name) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GetClusters provides a mock function with given fields: project +func (_m *ProjectGetter) GetClusters(project string) ([]*v1alpha1.Cluster, error) { + ret := _m.Called(project) + + var r0 []*v1alpha1.Cluster + if rf, ok := ret.Get(0).(func(string) []*v1alpha1.Cluster); ok { + r0 = rf(project) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*v1alpha1.Cluster) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(project) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTNewProjectGetter interface { + mock.TestingT + Cleanup(func()) +} + +// NewProjectGetter creates a new instance of ProjectGetter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewProjectGetter(t mockConstructorTestingTNewProjectGetter) *ProjectGetter { + mock := &ProjectGetter{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/server/extension/mocks/RbacEnforcer.go b/server/extension/mocks/RbacEnforcer.go new file mode 100644 index 0000000000000..01fb0c7421c69 --- /dev/null +++ b/server/extension/mocks/RbacEnforcer.go @@ -0,0 +1,41 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// RbacEnforcer is an autogenerated mock type for the RbacEnforcer type +type RbacEnforcer struct { + mock.Mock +} + +// EnforceErr provides a mock function with given fields: rvals +func (_m *RbacEnforcer) EnforceErr(rvals ...interface{}) error { + var _ca []interface{} + _ca = append(_ca, rvals...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(...interface{}) error); ok { + r0 = rf(rvals...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +type mockConstructorTestingTNewRbacEnforcer interface { + mock.TestingT + Cleanup(func()) +} + +// NewRbacEnforcer creates a new instance of RbacEnforcer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewRbacEnforcer(t mockConstructorTestingTNewRbacEnforcer) *RbacEnforcer { + mock := &RbacEnforcer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/server/logout/logout.go b/server/logout/logout.go index e2bfa81f28bfb..e49f815931596 100644 --- a/server/logout/logout.go +++ b/server/logout/logout.go @@ -19,7 +19,7 @@ import ( "github.com/argoproj/argo-cd/v2/util/settings" ) -//NewHandler creates handler serving to do api/logout endpoint +// NewHandler creates handler serving to do api/logout endpoint func NewHandler(appClientset versioned.Interface, settingsMrg *settings.SettingsManager, sessionMgr *session.SessionManager, rootPath, baseHRef, namespace string) *Handler { return &Handler{ appClientset: appClientset, diff --git a/server/logout/logout_test.go b/server/logout/logout_test.go index 692e741aa3c2f..e20d35837f475 100644 --- a/server/logout/logout_test.go +++ b/server/logout/logout_test.go @@ -251,17 +251,17 @@ func TestHandlerConstructLogoutURL(t *testing.T) { invalidHeader := make(map[string][]string) invalidHeader["Cookie"] = []string{"argocd.token=" + invalidToken} - oidcRequest, err := http.NewRequest("GET", "http://localhost:4000/api/logout", nil) + oidcRequest, err := http.NewRequest(http.MethodGet, "http://localhost:4000/api/logout", nil) assert.NoError(t, err) oidcRequest.Header = oidcTokenHeader - nonoidcRequest, err := http.NewRequest("GET", "http://localhost:4000/api/logout", nil) + nonoidcRequest, err := http.NewRequest(http.MethodGet, "http://localhost:4000/api/logout", nil) assert.NoError(t, err) nonoidcRequest.Header = nonOidcTokenHeader assert.NoError(t, err) - requestWithInvalidToken, err := http.NewRequest("GET", "http://localhost:4000/api/logout", nil) + requestWithInvalidToken, err := http.NewRequest(http.MethodGet, "http://localhost:4000/api/logout", nil) assert.NoError(t, err) requestWithInvalidToken.Header = invalidHeader - invalidRequest, err := http.NewRequest("GET", "http://localhost:4000/api/logout", nil) + invalidRequest, err := http.NewRequest(http.MethodGet, "http://localhost:4000/api/logout", nil) assert.NoError(t, err) tests := []struct { 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/project/project.go b/server/project/project.go index cdb2214c1607f..44ddee95eaaff 100644 --- a/server/project/project.go +++ b/server/project/project.go @@ -172,6 +172,9 @@ func (s *Server) ListLinks(ctx context.Context, q *project.ListProjectLinksReque return nil, err } + // sanitize project jwt tokens + proj.Status = v1alpha1.AppProjectStatus{} + obj, err := kube.ToUnstructured(proj) if err != nil { return nil, fmt.Errorf("error getting application: %w", err) @@ -182,7 +185,8 @@ func (s *Server) ListLinks(ctx context.Context, q *project.ListProjectLinksReque return nil, fmt.Errorf("failed to read application deep links from configmap: %w", err) } - finalList, errorList := deeplinks.EvaluateDeepLinksResponse(*obj, deepLinks) + deeplinksObj := deeplinks.CreateDeepLinksObject(nil, nil, nil, obj) + finalList, errorList := deeplinks.EvaluateDeepLinksResponse(deeplinksObj, obj.GetName(), deepLinks) if len(errorList) > 0 { log.Errorf("errorList while evaluating project deep links, %v", strings.Join(errorList, ", ")) } @@ -503,7 +507,7 @@ func (s *Server) logEvent(a *v1alpha1.AppProject, ctx context.Context, reason st user = "Unknown user" } message := fmt.Sprintf("%s %s", user, action) - s.auditLogger.LogAppProjEvent(a, eventInfo, message) + s.auditLogger.LogAppProjEvent(a, eventInfo, message, user) } func (s *Server) GetSyncWindowsState(ctx context.Context, q *project.SyncWindowsQuery) (*project.SyncWindowsResponse, error) { diff --git a/server/rbacpolicy/rbacpolicy.go b/server/rbacpolicy/rbacpolicy.go index 1ec420b642fdb..940f5bfe70844 100644 --- a/server/rbacpolicy/rbacpolicy.go +++ b/server/rbacpolicy/rbacpolicy.go @@ -3,7 +3,7 @@ package rbacpolicy import ( "strings" - jwt "github.com/golang-jwt/jwt/v4" + "github.com/golang-jwt/jwt/v4" log "github.com/sirupsen/logrus" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" @@ -24,6 +24,7 @@ const ( ResourceGPGKeys = "gpgkeys" ResourceLogs = "logs" ResourceExec = "exec" + ResourceExtensions = "extensions" // please add new items to Actions ActionGet = "get" @@ -33,6 +34,7 @@ const ( ActionSync = "sync" ActionOverride = "override" ActionAction = "action" + ActionInvoke = "invoke" ) var ( @@ -152,7 +154,7 @@ func (p *RBACPolicyEnforcer) EnforceClaims(claims jwt.Claims, rvals ...interface } } } - logCtx := log.WithField("claims", claims).WithField("rval", rvals) + logCtx := log.WithFields(log.Fields{"claims": claims, "rval": rvals, "subject": subject, "groups": groups, "project": projName, "scopes": scopes}) logCtx.Debug("enforce failed") return false } diff --git a/server/repository/repository.go b/server/repository/repository.go index f623c11b2c023..417a41ee306ef 100644 --- a/server/repository/repository.go +++ b/server/repository/repository.go @@ -1,11 +1,10 @@ package repository import ( + "context" "fmt" "reflect" - "context" - "github.com/argoproj/gitops-engine/pkg/utils/kube" "github.com/argoproj/gitops-engine/pkg/utils/text" log "github.com/sirupsen/logrus" @@ -164,6 +163,7 @@ func (s *Server) Get(ctx context.Context, q *repositorypkg.RepoQuery) (*appsv1.R GitHubAppEnterpriseBaseURL: repo.GitHubAppEnterpriseBaseURL, Proxy: repo.Proxy, Project: repo.Project, + InheritedCreds: repo.InheritedCreds, } item.ConnectionState = s.getConnectionState(ctx, item.Repo, q.ForceRefresh) @@ -187,15 +187,17 @@ func (s *Server) ListRepositories(ctx context.Context, q *repositorypkg.RepoQuer } // remove secrets items = append(items, &appsv1.Repository{ - Repo: repo.Repo, - Type: rType, - Name: repo.Name, - Username: repo.Username, - Insecure: repo.IsInsecure(), - EnableLFS: repo.EnableLFS, - EnableOCI: repo.EnableOCI, - Proxy: repo.Proxy, - Project: repo.Project, + Repo: repo.Repo, + Type: rType, + Name: repo.Name, + Username: repo.Username, + Insecure: repo.IsInsecure(), + EnableLFS: repo.EnableLFS, + EnableOCI: repo.EnableOCI, + Proxy: repo.Proxy, + Project: repo.Project, + ForceHttpBasicAuth: repo.ForceHttpBasicAuth, + InheritedCreds: repo.InheritedCreds, }) } } @@ -292,7 +294,7 @@ func (s *Server) GetAppDetails(ctx context.Context, q *repositorypkg.RepoAppDeta if err := s.enf.EnforceErr(claims, rbacpolicy.ResourceRepositories, rbacpolicy.ActionGet, createRBACObject(repo.Project, repo.Repo)); err != nil { return nil, err } - appName, appNs := argo.ParseAppQualifiedName(q.AppName, s.settings.GetNamespace()) + appName, appNs := argo.ParseFromQualifiedName(q.AppName, s.settings.GetNamespace()) app, err := s.appLister.Applications(appNs).Get(appName) appRBACObj := createRBACObject(q.AppProject, q.AppName) // ensure caller has read privileges to app @@ -558,16 +560,23 @@ func (s *Server) isRepoPermittedInProject(ctx context.Context, repo string, proj // isSourceInHistory checks if the supplied application source is either our current application // source, or was something which we synced to previously. func isSourceInHistory(app *v1alpha1.Application, source v1alpha1.ApplicationSource) bool { - if source.Equals(app.Spec.GetSource()) { + appSource := app.Spec.GetSource() + if source.Equals(&appSource) { return true } + appSources := app.Spec.GetSources() + for _, s := range appSources { + if source.Equals(&s) { + return true + } + } // Iterate history. When comparing items in our history, use the actual synced revision to // compare with the supplied source.targetRevision in the request. This is because // history[].source.targetRevision is ambiguous (e.g. HEAD), whereas // history[].revision will contain the explicit SHA for _, h := range app.Status.History { h.Source.TargetRevision = h.Revision - if source.Equals(h.Source) { + if source.Equals(&h.Source) { return true } } diff --git a/server/repository/repository.proto b/server/repository/repository.proto index f941932cf2dae..6466967702e85 100644 --- a/server/repository/repository.proto +++ b/server/repository/repository.proto @@ -81,6 +81,8 @@ message RepoAccessQuery { string project = 17; // Google Cloud Platform service account key string gcpServiceAccountKey = 18; + // Whether to force HTTP basic auth + bool forceHttpBasicAuth = 19; } message RepoResponse {} diff --git a/server/repository/repository_test.go b/server/repository/repository_test.go index cdd7ba89c30b7..55bf7ab7220ac 100644 --- a/server/repository/repository_test.go +++ b/server/repository/repository_test.go @@ -34,6 +34,8 @@ import ( dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks" "github.com/argoproj/argo-cd/v2/util/rbac" "github.com/argoproj/argo-cd/v2/util/settings" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application" ) const testNamespace = "default" @@ -60,7 +62,7 @@ var ( } defaultProj = &appsv1.AppProject{ TypeMeta: metav1.TypeMeta{ - Kind: "AppProject", + Kind: application.AppProjectKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -75,7 +77,7 @@ var ( defaultProjNoSources = &appsv1.AppProject{ TypeMeta: metav1.TypeMeta{ - Kind: "AppProject", + Kind: application.AppProjectKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -87,10 +89,21 @@ var ( Destinations: []appsv1.ApplicationDestination{{Server: "*", Namespace: "*"}}, }, } - + fakeRepo = appsv1.Repository{ + Repo: "https://test", + Type: "test", + Name: "test", + Username: "argo", + Insecure: false, + EnableLFS: false, + EnableOCI: false, + Proxy: "test", + Project: "argocd", + InheritedCreds: true, + } guestbookApp = &appsv1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ @@ -122,6 +135,96 @@ var ( }, }, } + multiSourceApp001AppName = "msa-two-helm-types" + multiSourceApp001 = &appsv1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: multiSourceApp001AppName, + Namespace: testNamespace, + }, + Spec: appsv1.ApplicationSpec{ + Project: "default", + Sources: []appsv1.ApplicationSource{ + { + RepoURL: "https://helm.elastic.co", + TargetRevision: "7.7.0", + Chart: "elasticsearch", + Helm: &appsv1.ApplicationSourceHelm{ + ValueFiles: []string{"values.yaml"}, + }, + }, + { + RepoURL: "https://helm.elastic.co", + TargetRevision: "7.6.0", + Chart: "elasticsearch", + Helm: &appsv1.ApplicationSourceHelm{ + ValueFiles: []string{"values.yaml"}, + }, + }, + }, + }, + Status: appsv1.ApplicationStatus{ + History: appsv1.RevisionHistories{ + { + Revision: "HEAD", + Sources: []appsv1.ApplicationSource{ + { + RepoURL: "https://helm.elastic.co", + TargetRevision: "7.6.0", + Helm: &appsv1.ApplicationSourceHelm{ + ValueFiles: []string{"values-old.yaml"}, + }, + }, + }, + }, + }, + }, + } + multiSourceApp002AppName = "msa-one-plugin-one-helm" + multiSourceApp002 = &appsv1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: multiSourceApp002AppName, + Namespace: testNamespace, + }, + Spec: appsv1.ApplicationSpec{ + Project: "default", + Sources: []appsv1.ApplicationSource{ + { + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + Path: "sock-shop", + TargetRevision: "HEAD", + }, + { + RepoURL: "https://helm.elastic.co", + TargetRevision: "7.7.0", + Chart: "elasticsearch", + Helm: &appsv1.ApplicationSourceHelm{ + ValueFiles: []string{"values.yaml"}, + }, + }, + }, + }, + Status: appsv1.ApplicationStatus{ + History: appsv1.RevisionHistories{ + { + Revision: "HEAD", + Sources: []appsv1.ApplicationSource{ + { + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "1.0.0", + }, + }, + }, + }, + }, + } ) func newAppAndProjLister(objects ...runtime.Object) (applisters.ApplicationLister, k8scache.SharedIndexInformer) { @@ -196,6 +299,33 @@ func TestRepositoryServer(t *testing.T) { assert.Equal(t, repo.Repo, url) }) + t.Run("Test_GetInherited", func(t *testing.T) { + repoServerClient := mocks.RepoServerServiceClient{} + repoServerClient.On("TestRepository", mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil) + repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient} + + url := "https://test" + db := &dbmocks.ArgoDB{} + testRepo := &appsv1.Repository{ + Repo: url, + Type: "git", + Username: "foo", + InheritedCreds: true, + } + db.On("GetRepository", context.TODO(), url).Return(testRepo, nil) + db.On("RepositoryExists", context.TODO(), url).Return(true, nil) + + s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projInformer, testNamespace, settingsMgr) + repo, err := s.Get(context.TODO(), &repository.RepoQuery{ + Repo: url, + }) + assert.Nil(t, err) + + testRepo.ConnectionState = repo.ConnectionState // overwrite connection state on our test object to simplify comparison below + + assert.Equal(t, testRepo, repo) + }) + t.Run("Test_GetWithErrorShouldReturn403", func(t *testing.T) { repoServerClient := mocks.RepoServerServiceClient{} repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient} @@ -279,6 +409,23 @@ func TestRepositoryServer(t *testing.T) { assert.Equal(t, repo.Repo, "test") }) + t.Run("Test_ListRepositories", func(t *testing.T) { + repoServerClient := mocks.RepoServerServiceClient{} + repoServerClient.On("TestRepository", mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil) + repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient} + enforcer := newEnforcer(kubeclientset) + + url := "https://test" + db := &dbmocks.ArgoDB{} + db.On("GetRepository", context.TODO(), url).Return(nil, nil) + db.On("ListHelmRepositories", context.TODO(), mock.Anything).Return(nil, nil) + db.On("ListRepositories", context.TODO()).Return([]*appsv1.Repository{&fakeRepo, &fakeRepo}, nil) + + s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projInformer, testNamespace, settingsMgr) + resp, err := s.ListRepositories(context.TODO(), &repository.RepoQuery{}) + assert.NoError(t, err) + assert.Equal(t, 2, len(resp.Items)) + }) } func TestRepositoryServerListApps(t *testing.T) { @@ -507,13 +654,92 @@ func TestRepositoryServerGetAppDetails(t *testing.T) { s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, testNamespace, settingsMgr) resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{ - Source: guestbookApp.Spec.GetSourcePtr(), + Source: guestbookApp.Spec.GetSourcePtr(0), AppName: "guestbook", AppProject: "default", }) assert.NoError(t, err) assert.Equal(t, expectedResp, *resp) }) + t.Run("Test_ExistingMultiSourceApp001", func(t *testing.T) { + repoServerClient := mocks.RepoServerServiceClient{} + repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient} + enforcer := newEnforcer(kubeclientset) + + url := "https://helm.elastic.co" + helmRepos := []*appsv1.Repository{{Repo: url}, {Repo: url}} + db := &dbmocks.ArgoDB{} + db.On("ListHelmRepositories", context.TODO(), mock.Anything).Return(helmRepos, nil) + db.On("GetRepository", context.TODO(), url).Return(&appsv1.Repository{Repo: url}, nil) + db.On("GetProjectRepositories", context.TODO(), "default").Return(nil, nil) + db.On("GetProjectClusters", context.TODO(), "default").Return(nil, nil) + expectedResp := apiclient.RepoAppDetailsResponse{Type: "Helm"} + repoServerClient.On("GetAppDetails", context.TODO(), mock.Anything).Return(&expectedResp, nil) + appLister, projLister := newAppAndProjLister(defaultProj, multiSourceApp001) + + s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, testNamespace, settingsMgr) + sources := multiSourceApp001.Spec.GetSources() + assert.Equal(t, 2, len(sources)) + resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{ + Source: &sources[0], + AppName: multiSourceApp001AppName, + AppProject: "default", + }) + assert.NoError(t, err) + assert.Equal(t, expectedResp, *resp) + assert.Equal(t, "Helm", resp.Type) + // Next source + resp, err = s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{ + Source: &sources[1], + AppName: multiSourceApp001AppName, + AppProject: "default", + }) + assert.NoError(t, err) + assert.Equal(t, expectedResp, *resp) + assert.Equal(t, "Helm", resp.Type) + }) + t.Run("Test_ExistingMultiSourceApp002", func(t *testing.T) { + repoServerClient := mocks.RepoServerServiceClient{} + repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient} + enforcer := newEnforcer(kubeclientset) + + url0 := "https://github.com/argoproj/argocd-example-apps.git" + url1 := "https://helm.elastic.co" + helmRepos := []*appsv1.Repository{{Repo: url0}, {Repo: url1}} + db := &dbmocks.ArgoDB{} + db.On("ListHelmRepositories", context.TODO(), mock.Anything).Return(helmRepos, nil) + db.On("GetRepository", context.TODO(), url0).Return(&appsv1.Repository{Repo: url0}, nil) + db.On("GetRepository", context.TODO(), url1).Return(&appsv1.Repository{Repo: url1}, nil) + db.On("GetProjectRepositories", context.TODO(), "default").Return(nil, nil) + db.On("GetProjectClusters", context.TODO(), "default").Return(nil, nil) + expectedResp0 := apiclient.RepoAppDetailsResponse{Type: "Plugin"} + expectedResp1 := apiclient.RepoAppDetailsResponse{Type: "Helm"} + repoServerClient.On("GetAppDetails", context.TODO(), mock.MatchedBy(func(req *apiclient.RepoServerAppDetailsQuery) bool { return req.Source.RepoURL == url0 })).Return(&expectedResp0, nil) + repoServerClient.On("GetAppDetails", context.TODO(), mock.MatchedBy(func(req *apiclient.RepoServerAppDetailsQuery) bool { return req.Source.RepoURL == url1 })).Return(&expectedResp1, nil) + appLister, projLister := newAppAndProjLister(defaultProj, multiSourceApp002) + + s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, testNamespace, settingsMgr) + sources := multiSourceApp002.Spec.GetSources() + assert.Equal(t, 2, len(sources)) + + resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{ + Source: &sources[0], + AppName: multiSourceApp002AppName, + AppProject: "default", + }) + assert.NoError(t, err) + assert.Equal(t, "Plugin", resp.Type) + assert.Equal(t, expectedResp0, *resp) + // Next source + resp, err = s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{ + Source: &sources[1], + AppName: multiSourceApp002AppName, + AppProject: "default", + }) + assert.NoError(t, err) + assert.Equal(t, expectedResp1, *resp) + assert.Equal(t, "Helm", resp.Type) + }) t.Run("Test_ExistingAppMismatchedProjectName", func(t *testing.T) { repoServerClient := mocks.RepoServerServiceClient{} repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient} @@ -526,7 +752,7 @@ func TestRepositoryServerGetAppDetails(t *testing.T) { s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, testNamespace, settingsMgr) resp, err := s.GetAppDetails(context.TODO(), &repository.RepoAppDetailsQuery{ - Source: guestbookApp.Spec.GetSourcePtr(), + Source: guestbookApp.Spec.GetSourcePtr(0), AppName: "guestbook", AppProject: "mismatch", }) diff --git a/server/server.go b/server/server.go index f1302a0f12f45..625fa2053023e 100644 --- a/server/server.go +++ b/server/server.go @@ -2,7 +2,6 @@ package server import ( "context" - netCtx "context" "crypto/tls" "errors" "fmt" @@ -25,19 +24,20 @@ import ( // nolint:staticcheck golang_proto "github.com/golang/protobuf/proto" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" "github.com/argoproj/notifications-engine/pkg/api" "github.com/argoproj/pkg/sync" - "github.com/go-redis/redis/v8" "github.com/golang-jwt/jwt/v4" "github.com/gorilla/handlers" - gmux "github.com/gorilla/mux" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth" grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/improbable-eng/grpc-web/go/grpcweb" + "github.com/redis/go-redis/v9" log "github.com/sirupsen/logrus" "github.com/soheilhy/cmux" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" @@ -61,7 +61,6 @@ import ( "github.com/argoproj/argo-cd/v2/pkg/apiclient" accountpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/account" applicationpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" - applicationsetpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/applicationset" certificatepkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/certificate" clusterpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/cluster" @@ -102,7 +101,6 @@ import ( "github.com/argoproj/argo-cd/v2/util/assets" cacheutil "github.com/argoproj/argo-cd/v2/util/cache" "github.com/argoproj/argo-cd/v2/util/db" - "github.com/argoproj/argo-cd/v2/util/dex" dexutil "github.com/argoproj/argo-cd/v2/util/dex" "github.com/argoproj/argo-cd/v2/util/env" errorsutil "github.com/argoproj/argo-cd/v2/util/errors" @@ -161,7 +159,7 @@ func init() { if replicasCount > 0 { maxConcurrentLoginRequestsCount = maxConcurrentLoginRequestsCount / replicasCount } - enableGRPCTimeHistogram = os.Getenv(common.EnvEnableGRPCTimeHistogramEnv) == "true" + enableGRPCTimeHistogram = env.ParseBoolFromEnv(common.EnvEnableGRPCTimeHistogramEnv, false) } // ArgoCDServer is the API server for Argo CD @@ -180,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 @@ -194,33 +192,49 @@ type ArgoCDServer struct { secretInformer cache.SharedIndexInformer configMapInformer cache.SharedIndexInformer serviceSet *ArgoCDServiceSet + extensionManager *extension.Manager } type ArgoCDServerOpts struct { DisableAuth bool + ContentTypes []string EnableGZip bool Insecure bool StaticAssetsDir string ListenPort int + ListenHost string MetricsPort int + MetricsHost string Namespace string DexServerAddr string - DexTLSConfig *dex.DexTLSConfig + DexTLSConfig *dexutil.DexTLSConfig BaseHRef string RootPath string KubeClientset kubernetes.Interface AppClientset appclientset.Interface RepoClientset repoapiclient.Clientset Cache *servercache.Cache + RepoServerCache *repocache.Cache RedisClient *redis.Client TLSConfigCustomizer tlsutil.ConfigCustomizer XFrameOptions string ContentSecurityPolicy string - ListenHost string ApplicationNamespaces []string 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,11 +302,19 @@ 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) - return &ArgoCDServer{ + dbInstance := db.NewDB(opts.Namespace, settingsMgr, opts.KubeClientset) + logger := log.NewEntry(log.StandardLogger()) + + sg := extension.NewDefaultSettingsGetter(settingsMgr) + ag := extension.NewDefaultApplicationGetter(appLister) + pg := extension.NewDefaultProjectGetter(projLister, dbInstance) + em := extension.NewManager(logger, sg, ag, pg, enf) + + a := &ArgoCDServer{ ArgoCDServerOpts: opts, - log: log.NewEntry(log.StandardLogger()), + log: logger, settings: settings, sessionMgr: sessionMgr, settingsMgr: settingsMgr, @@ -306,11 +328,20 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer { policyEnforcer: policyEnf, userStateStorage: userStateStorage, staticAssets: http.FS(staticFS), - db: db.NewDB(opts.Namespace, settingsMgr, opts.KubeClientset), + db: dbInstance, apiFactory: apiFactory, secretInformer: secretInformer, configMapInformer: configMapInformer, + extensionManager: em, + } + + err = a.logInClusterWarnings() + if err != nil { + // Just log. It's not critical. + log.Warnf("Failed to log in-cluster warnings: %v", err) } + + return a } const ( @@ -357,6 +388,47 @@ func (l *Listeners) Close() error { return nil } +// logInClusterWarnings checks the in-cluster configuration and prints out any warnings. +func (a *ArgoCDServer) logInClusterWarnings() error { + labelSelector := labels.NewSelector() + req, err := labels.NewRequirement(common.LabelKeySecretType, selection.Equals, []string{common.LabelValueSecretTypeCluster}) + if err != nil { + return fmt.Errorf("failed to construct cluster-type label selector: %w", err) + } + labelSelector = labelSelector.Add(*req) + secretsLister, err := a.settingsMgr.GetSecretsLister() + if err != nil { + return fmt.Errorf("failed to get secrets lister: %w", err) + } + clusterSecrets, err := secretsLister.Secrets(a.ArgoCDServerOpts.Namespace).List(labelSelector) + if err != nil { + return fmt.Errorf("failed to list cluster secrets: %w", err) + } + var inClusterSecrets []string + for _, clusterSecret := range clusterSecrets { + cluster, err := db.SecretToCluster(clusterSecret) + if err != nil { + return fmt.Errorf("could not unmarshal cluster secret %q: %w", clusterSecret.Name, err) + } + if cluster.Server == v1alpha1.KubernetesInternalAPIServerAddr { + inClusterSecrets = append(inClusterSecrets, clusterSecret.Name) + } + } + if len(inClusterSecrets) > 0 { + // Don't make this call unless we actually have in-cluster secrets, to save time. + dbSettings, err := a.settingsMgr.GetSettings() + if err != nil { + return fmt.Errorf("could not get DB settings: %w", err) + } + if !dbSettings.InClusterEnabled { + for _, clusterName := range inClusterSecrets { + log.Warnf("cluster %q uses in-cluster server address but it's disabled in Argo CD settings", clusterName) + } + } + } + return nil +} + func startListener(host string, port int) (net.Listener, error) { var conn net.Listener var realErr error @@ -383,8 +455,8 @@ func (a *ArgoCDServer) Listen() (*Listeners, error) { var dOpts []grpc.DialOption dOpts = append(dOpts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(apiclient.MaxGRPCMessageSize))) dOpts = append(dOpts, grpc.WithUserAgent(fmt.Sprintf("%s/%s", common.ArgoCDUserAgentName, common.GetVersion().Version))) - dOpts = append(dOpts, grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor())) - dOpts = append(dOpts, grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor())) + dOpts = append(dOpts, grpc.WithUnaryInterceptor(grpc_util.OTELUnaryClientInterceptor())) + dOpts = append(dOpts, grpc.WithStreamInterceptor(grpc_util.OTELStreamClientInterceptor())) if a.useTLS() { // The following sets up the dial Options for grpc-gateway to talk to gRPC server over TLS. // grpc-gateway is just translating HTTP/HTTPS requests as gRPC requests over localhost, @@ -413,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()) } @@ -423,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() @@ -431,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) @@ -447,11 +526,6 @@ func (a *ArgoCDServer) Run(ctx context.Context, listeners *Listeners) { httpsS.Handler = &bug21955Workaround{handler: httpsS.Handler} } - metricsServ := metrics.NewMetricsServer(a.ListenHost, 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 @@ -459,17 +533,18 @@ func (a *ArgoCDServer) Run(ctx context.Context, listeners *Listeners) { var httpL net.Listener var httpsL net.Listener if !a.useTLS() { - httpL = tcpm.Match(cmux.HTTP1Fast()) + httpL = tcpm.Match(cmux.HTTP1Fast("PATCH")) grpcL = tcpm.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc")) } else { // We first match on HTTP 1.1 methods. - httpL = tcpm.Match(cmux.HTTP1Fast()) + httpL = tcpm.Match(cmux.HTTP1Fast("PATCH")) // If not matched, we assume that its TLS. tlsl := tcpm.Match(cmux.Any()) - tlsConfig := tls.Config{ - Certificates: []tls.Certificate{*a.settings.Certificate}, + tlsConfig := tls.Config{} + tlsConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { + return a.settings.Certificate, nil } if a.TLSConfigCustomizer != nil { a.TLSConfigCustomizer(&tlsConfig) @@ -478,7 +553,7 @@ func (a *ArgoCDServer) Run(ctx context.Context, listeners *Listeners) { // Now, we build another mux recursively to match HTTPS and gRPC. tlsm = cmux.New(tlsl) - httpsL = tlsm.Match(cmux.HTTP1Fast()) + httpsL = tlsm.Match(cmux.HTTP1Fast("PATCH")) grpcL = tlsm.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc")) } @@ -557,13 +632,14 @@ func (a *ArgoCDServer) watchSettings() { prevURL := a.settings.URL prevOIDCConfig := a.settings.OIDCConfig() - prevDexCfgBytes, err := dex.GenerateDexConfigYAML(a.settings, a.DexTLSConfig == nil || a.DexTLSConfig.DisableTLS) + prevDexCfgBytes, err := dexutil.GenerateDexConfigYAML(a.settings, a.DexTLSConfig == nil || a.DexTLSConfig.DisableTLS) errorsutil.CheckError(err) prevGitHubSecret := a.settings.WebhookGitHubSecret prevGitLabSecret := a.settings.WebhookGitLabSecret prevBitbucketUUID := a.settings.WebhookBitbucketUUID prevBitbucketServerSecret := a.settings.WebhookBitbucketServerSecret prevGogsSecret := a.settings.WebhookGogsSecret + prevExtConfig := a.settings.ExtensionConfig var prevCert, prevCertKey string if a.settings.Certificate != nil && !a.ArgoCDServerOpts.Insecure { prevCert, prevCertKey = tlsutil.EncodeX509KeyPairString(*a.settings.Certificate) @@ -572,7 +648,7 @@ func (a *ArgoCDServer) watchSettings() { for { newSettings := <-updateCh a.settings = newSettings - newDexCfgBytes, err := dex.GenerateDexConfigYAML(a.settings, a.DexTLSConfig == nil || a.DexTLSConfig.DisableTLS) + newDexCfgBytes, err := dexutil.GenerateDexConfigYAML(a.settings, a.DexTLSConfig == nil || a.DexTLSConfig.DisableTLS) errorsutil.CheckError(err) if string(newDexCfgBytes) != string(prevDexCfgBytes) { log.Infof("dex config modified. restarting") @@ -606,14 +682,24 @@ func (a *ArgoCDServer) watchSettings() { log.Infof("gogs secret modified. restarting") break } + if prevExtConfig != a.settings.ExtensionConfig { + prevExtConfig = a.settings.ExtensionConfig + log.Infof("extensions configs modified. Updating proxy registry...") + err := a.extensionManager.UpdateExtensionRegistry(a.settings) + if err != nil { + log.Errorf("error updating extensions configs: %s", err) + } else { + log.Info("extensions configs updated successfully") + } + } if !a.ArgoCDServerOpts.Insecure { var newCert, newCertKey string if a.settings.Certificate != nil { newCert, newCertKey = tlsutil.EncodeX509KeyPairString(*a.settings.Certificate) } if newCert != prevCert || newCertKey != prevCertKey { - log.Infof("tls certificate modified. restarting") - break + log.Infof("tls certificate modified. reloading certificate") + // No need to break out of this loop since TlsConfig.GetCertificate will automagically reload the cert. } } } @@ -661,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(), }, ), } @@ -679,6 +765,8 @@ func (a *ArgoCDServer) newGRPCServer() (*grpc.Server, application.AppResourceTre "/repocreds.RepoCredsService/CreateRepositoryCredentials": true, "/repocreds.RepoCredsService/UpdateRepositoryCredentials": true, "/application.ApplicationService/PatchResource": true, + // Remove from logs both because the contents are sensitive and because they may be very large. + "/application.ApplicationService/GetManifestsWithFiles": true, } // NOTE: notice we do not configure the gRPC server here with TLS (e.g. grpc.Creds(creds)) // This is because TLS handshaking occurs in cmux handling @@ -688,7 +776,7 @@ func (a *ArgoCDServer) newGRPCServer() (*grpc.Server, application.AppResourceTre grpc_prometheus.StreamServerInterceptor, grpc_auth.StreamServerInterceptor(a.Authenticate), grpc_util.UserAgentStreamServerInterceptor(common.ArgoCDUserAgentName, clientConstraint), - grpc_util.PayloadStreamServerInterceptor(a.log, true, func(ctx netCtx.Context, fullMethodName string, servingObject interface{}) bool { + grpc_util.PayloadStreamServerInterceptor(a.log, true, func(ctx context.Context, fullMethodName string, servingObject interface{}) bool { return !sensitiveMethods[fullMethodName] }), grpc_util.ErrorCodeK8sStreamServerInterceptor(), @@ -702,7 +790,7 @@ func (a *ArgoCDServer) newGRPCServer() (*grpc.Server, application.AppResourceTre grpc_prometheus.UnaryServerInterceptor, grpc_auth.UnaryServerInterceptor(a.Authenticate), grpc_util.UserAgentUnaryServerInterceptor(common.ArgoCDUserAgentName, clientConstraint), - grpc_util.PayloadUnaryServerInterceptor(a.log, true, func(ctx netCtx.Context, fullMethodName string, servingObject interface{}) bool { + grpc_util.PayloadUnaryServerInterceptor(a.log, true, func(ctx context.Context, fullMethodName string, servingObject interface{}) bool { return !sensitiveMethods[fullMethodName] }), grpc_util.ErrorCodeK8sUnaryServerInterceptor(), @@ -765,6 +853,7 @@ func newArgoCDServiceSet(a *ArgoCDServer) *ArgoCDServiceSet { a.AppClientset, a.appLister, a.appInformer, + nil, a.RepoClientset, a.Cache, kubectl, @@ -775,7 +864,19 @@ func newArgoCDServiceSet(a *ArgoCDServer) *ArgoCDServiceSet { a.projInformer, a.ApplicationNamespaces) - applicationSetService := applicationset.NewServer(a.db, a.KubeClientset, a.enf, a.Cache, a.AppClientset, a.appLister, a.appsetInformer, a.appsetLister, a.projLister, a.settingsMgr, a.Namespace, projectLock) + applicationSetService := applicationset.NewServer( + a.db, + a.KubeClientset, + a.enf, + a.AppClientset, + a.appsetInformer, + a.appsetLister, + a.projLister, + a.settingsMgr, + a.Namespace, + projectLock, + a.ApplicationNamespaces) + projectService := project.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.enf, projectLock, a.sessionMgr, a.policyEnforcer, a.projInformer, a.settingsMgr, a.db) appsInAnyNamespaceEnabled := len(a.ArgoCDServerOpts.ApplicationNamespaces) > 0 settingsService := settings.NewServer(a.settingsMgr, a.RepoClientset, a, a.DisableAuth, appsInAnyNamespaceEnabled) @@ -872,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{ @@ -880,7 +981,7 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl Handler: &handlerSwitcher{ handler: mux, urlToHandler: map[string]http.Handler{ - "/api/badge": badge.NewHandler(a.AppClientset, a.settingsMgr, a.Namespace), + "/api/badge": badge.NewHandler(a.AppClientset, a.settingsMgr, a.Namespace, a.ApplicationNamespaces), common.LogoutEndpoint: logout.NewHandler(a.AppClientset, a.settingsMgr, a.sessionMgr, a.ArgoCDServerOpts.RootPath, a.ArgoCDServerOpts.BaseHRef, a.Namespace), }, contentTypeToHandler: map[string]http.Handler{ @@ -903,22 +1004,27 @@ 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). + terminal := application.NewHandler(a.appLister, a.Namespace, a.ApplicationNamespaces, a.db, a.enf, a.Cache, appResourceTreeFn, a.settings.ExecShells, a.sessionMgr). WithFeatureFlagMiddleware(a.settingsMgr.GetSettings) th := util_session.WithAuthMiddleware(a.DisableAuth, a.sessionMgr, terminal) mux.Handle("/terminal", th) - // Dead code for now - // Proxy extension is currently an experimental feature and is disabled + // Proxy extension is currently an alpha feature and is disabled // by default. - // if a.EnableProxyExtension { - // // 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) - // } + if a.EnableProxyExtension { + // 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, metricsReg) + } + mustRegisterGWHandler(versionpkg.RegisterVersionServiceHandler, ctx, gwmux, conn) mustRegisterGWHandler(clusterpkg.RegisterClusterServiceHandler, ctx, gwmux, conn) mustRegisterGWHandler(applicationpkg.RegisterApplicationServiceHandler, ctx, gwmux, conn) @@ -942,7 +1048,8 @@ 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.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) // Serve cli binaries directly from API server @@ -951,9 +1058,13 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl // Serve extensions var extensionsSharedPath = "/tmp/extensions/" - mux.HandleFunc("/extensions.js", func(writer http.ResponseWriter, _ *http.Request) { + var extensionsHandler http.Handler = http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) { a.serveExtensions(extensionsSharedPath, writer) }) + if a.ArgoCDServerOpts.EnableGZip { + extensionsHandler = compressHandler(extensionsHandler) + } + mux.Handle("/extensions.js", extensionsHandler) // Serve UI static assets var assetsHandler http.Handler = http.HandlerFunc(a.newStaticAssetsHandler()) @@ -964,22 +1075,36 @@ 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. -// nolint:deadcode,unused,staticcheck -func registerExtensions(mux *http.ServeMux, a *ArgoCDServer) { - sg := extension.NewDefaultSettingsGetter(a.settingsMgr) - ag := extension.NewDefaultApplicationGetter(a.serviceSet.ApplicationService) - em := extension.NewManager(sg, ag, a.log) - r := gmux.NewRouter() - - err := em.RegisterHandlers(r) +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 extension handlers: %s", err) - return + a.log.Errorf("Error registering extensions: %s", err) } - mux.Handle(fmt.Sprintf("%s/", extension.URLPrefix), r) } var extensionsPattern = regexp.MustCompile(`^extension(.*)\.js$`) @@ -1032,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) @@ -1141,7 +1266,11 @@ func (server *ArgoCDServer) newStaticAssetsHandler() func(http.ResponseWriter, * http.ServeContent(w, r, "index.html", modTime, io.NewByteReadSeeker(data)) } else { if isMainJsBundle(r.URL) { - w.Header().Set("Cache-Control", "public, max-age=31536000, immutable") + cacheControl := "public, max-age=31536000, immutable" + if !fileRequest { + cacheControl = "no-cache" + } + w.Header().Set("Cache-Control", cacheControl) } http.FileServer(server.staticAssets).ServeHTTP(w, r) } @@ -1222,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_norace_test.go b/server/server_norace_test.go index 5238351c03720..eaef2e67257d1 100644 --- a/server/server_norace_test.go +++ b/server/server_norace_test.go @@ -27,7 +27,7 @@ func TestUserAgent(t *testing.T) { // the data race, it APPEARS to be intentional, but in any case it's nothing we are doing in Argo CD // that is causing this issue. - s, closer := fakeServer() + s, closer := fakeServer(t) defer closer() lns, err := s.Listen() assert.NoError(t, err) @@ -94,7 +94,7 @@ func Test_StaticHeaders(t *testing.T) { // Test default policy "sameorigin" and "frame-ancestors 'self';" { - s, closer := fakeServer() + s, closer := fakeServer(t) defer closer() lns, err := s.Listen() assert.NoError(t, err) @@ -111,7 +111,7 @@ func Test_StaticHeaders(t *testing.T) { client := http.Client{} url := fmt.Sprintf("http://127.0.0.1:%d/test.html", s.ListenPort) - req, err := http.NewRequest("GET", url, nil) + req, err := http.NewRequest(http.MethodGet, url, nil) assert.NoError(t, err) resp, err := client.Do(req) assert.NoError(t, err) @@ -121,7 +121,7 @@ func Test_StaticHeaders(t *testing.T) { // Test custom policy for X-Frame-Options and Content-Security-Policy { - s, closer := fakeServer() + s, closer := fakeServer(t) defer closer() s.XFrameOptions = "deny" s.ContentSecurityPolicy = "frame-ancestors 'none';" @@ -140,7 +140,7 @@ func Test_StaticHeaders(t *testing.T) { client := http.Client{} url := fmt.Sprintf("http://127.0.0.1:%d/test.html", s.ListenPort) - req, err := http.NewRequest("GET", url, nil) + req, err := http.NewRequest(http.MethodGet, url, nil) assert.NoError(t, err) resp, err := client.Do(req) assert.NoError(t, err) @@ -150,7 +150,7 @@ func Test_StaticHeaders(t *testing.T) { // Test disabled X-Frame-Options and Content-Security-Policy { - s, closer := fakeServer() + s, closer := fakeServer(t) defer closer() s.XFrameOptions = "" s.ContentSecurityPolicy = "" @@ -172,7 +172,7 @@ func Test_StaticHeaders(t *testing.T) { client := http.Client{} url := fmt.Sprintf("http://127.0.0.1:%d/test.html", s.ListenPort) - req, err := http.NewRequest("GET", url, nil) + req, err := http.NewRequest(http.MethodGet, url, nil) assert.NoError(t, err) resp, err := client.Do(req) assert.NoError(t, err) diff --git a/server/server_test.go b/server/server_test.go index e4fdafee8bcd7..c4f4153f24d89 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -7,11 +7,12 @@ import ( "net/http" "net/http/httptest" "net/url" + "os" + "path/filepath" "strings" "testing" "time" - "github.com/ghodss/yaml" "github.com/golang-jwt/jwt/v4" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -19,6 +20,7 @@ import ( "google.golang.org/grpc/metadata" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/pkg/apiclient" @@ -30,13 +32,21 @@ 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" ) -func fakeServer() (*ArgoCDServer, func()) { +type FakeArgoCDServer struct { + *ArgoCDServer + TmpAssetsDir string +} + +func fakeServer(t *testing.T) (*FakeArgoCDServer, func()) { cm := test.NewFakeConfigMap() secret := test.NewFakeSecret() kubeclientset := fake.NewSimpleClientset(cm, secret) @@ -44,6 +54,7 @@ func fakeServer() (*ArgoCDServer, func()) { redis, closer := test.NewInMemoryRedis() port, err := test.GetFreePort() mockRepoClient := &mocks.Clientset{RepoServerServiceClient: &mocks.RepoServerServiceClient{}} + tmpAssetsDir := t.TempDir() if err != nil { panic(err) @@ -67,11 +78,13 @@ func fakeServer() (*ArgoCDServer, func()) { 1*time.Minute, 1*time.Minute, ), - RedisClient: redis, - RepoClientset: mockRepoClient, + RedisClient: redis, + RepoClientset: mockRepoClient, + StaticAssetsDir: tmpAssetsDir, } srv := NewServer(context.Background(), argoCDOpts) - return srv, closer + fakeSrv := &FakeArgoCDServer{srv, tmpAssetsDir} + return fakeSrv, closer } func TestEnforceProjectToken(t *testing.T) { @@ -392,7 +405,7 @@ func TestRevokedToken(t *testing.T) { } func TestCertsAreNotGeneratedInInsecureMode(t *testing.T) { - s, closer := fakeServer() + s, closer := fakeServer(t) defer closer() assert.True(t, s.Insecure) assert.Nil(t, s.settings.Certificate) @@ -517,12 +530,12 @@ func dexMockHandler(t *testing.T, url string) func(http.ResponseWriter, *http.Re t.Fail() } default: - w.WriteHeader(404) + w.WriteHeader(http.StatusNotFound) } } } -func getTestServer(t *testing.T, anonymousEnabled bool, withFakeSSO bool) (argocd *ArgoCDServer, dexURL 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" @@ -533,9 +546,14 @@ func getTestServer(t *testing.T, anonymousEnabled bool, withFakeSSO bool) (argoc ts.Config.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { dexMockHandler(t, ts.URL)(w, r) }) + oidcServer := ts + if !useDexForSSO { + oidcServer = testutil.GetOIDCTestServer(t) + } if withFakeSSO { cm.Data["url"] = ts.URL - cm.Data["dex.config"] = ` + if useDexForSSO { + cm.Data["dex.config"] = ` connectors: # OIDC - type: OIDC @@ -545,6 +563,18 @@ connectors: issuer: https://auth.example.gom clientID: test-client clientSecret: $dex.oidc.clientSecret` + } else { + // 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. + cm.Data["oidc.tls.insecure.skip.verify"] = "true" + } } secret := test.NewFakeSecret() kubeclientset := fake.NewSimpleClientset(cm, secret) @@ -556,27 +586,132 @@ connectors: AppClientset: appClientSet, RepoClientset: mockRepoClient, } - if withFakeSSO { + if withFakeSSO && useDexForSSO { argoCDOpts.DexServerAddr = ts.URL } argocd = NewServer(context.Background(), argoCDOpts) - return argocd, ts.URL + 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 + type testData struct { test string anonymousEnabled bool claims jwt.RegisteredClaims expectedErrorContains string expectedClaims interface{} + useDex bool } var tests = []testData{ + // Dex { test: "anonymous disabled, no audience", anonymousEnabled: false, - claims: jwt.RegisteredClaims{}, - expectedErrorContains: "no audience found in the token", + claims: jwt.RegisteredClaims{ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))}, + expectedErrorContains: common.TokenVerificationError, expectedClaims: nil, }, { @@ -589,31 +724,95 @@ func TestAuthenticate_3rd_party_JWTs(t *testing.T) { { test: "anonymous disabled, unexpired token, admin claim", anonymousEnabled: false, - claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))}, - expectedErrorContains: "id token signed with unsupported algorithm", + claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))}, + expectedErrorContains: common.TokenVerificationError, expectedClaims: nil, }, { test: "anonymous enabled, unexpired token, admin claim", anonymousEnabled: true, - claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))}, + claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))}, expectedErrorContains: "", expectedClaims: "", }, { test: "anonymous disabled, expired token, admin claim", anonymousEnabled: false, - claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())}, - expectedErrorContains: "token is expired", + claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())}, + expectedErrorContains: common.TokenVerificationError, expectedClaims: jwt.RegisteredClaims{Issuer: "sso"}, }, { test: "anonymous enabled, expired token, admin claim", anonymousEnabled: true, - claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())}, + claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())}, + expectedErrorContains: "", + expectedClaims: "", + }, + { + test: "anonymous disabled, unexpired token, admin claim, incorrect audience", + anonymousEnabled: false, + claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"incorrect-audience"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))}, + expectedErrorContains: common.TokenVerificationError, + expectedClaims: nil, + }, + // External OIDC (not bundled Dex) + { + test: "external OIDC: anonymous disabled, no audience", + anonymousEnabled: false, + claims: jwt.RegisteredClaims{ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))}, + useDex: true, + expectedErrorContains: common.TokenVerificationError, + expectedClaims: nil, + }, + { + test: "external OIDC: anonymous enabled, no audience", + anonymousEnabled: true, + claims: jwt.RegisteredClaims{}, + useDex: true, expectedErrorContains: "", expectedClaims: "", }, + { + test: "external OIDC: anonymous disabled, unexpired token, admin claim", + anonymousEnabled: false, + claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))}, + useDex: true, + expectedErrorContains: common.TokenVerificationError, + expectedClaims: nil, + }, + { + test: "external OIDC: anonymous enabled, unexpired token, admin claim", + anonymousEnabled: true, + claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))}, + useDex: true, + expectedErrorContains: "", + expectedClaims: "", + }, + { + test: "external OIDC: anonymous disabled, expired token, admin claim", + anonymousEnabled: false, + claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())}, + useDex: true, + expectedErrorContains: common.TokenVerificationError, + expectedClaims: jwt.RegisteredClaims{Issuer: "sso"}, + }, + { + test: "external OIDC: anonymous enabled, expired token, admin claim", + anonymousEnabled: true, + claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{common.ArgoCDClientAppID}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())}, + useDex: true, + expectedErrorContains: "", + expectedClaims: "", + }, + { + test: "external OIDC: anonymous disabled, unexpired token, admin claim, incorrect audience", + anonymousEnabled: false, + claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"incorrect-audience"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24))}, + useDex: true, + expectedErrorContains: common.TokenVerificationError, + expectedClaims: nil, + }, } for _, testData := range tests { @@ -625,8 +824,13 @@ func TestAuthenticate_3rd_party_JWTs(t *testing.T) { // Must be declared here to avoid race. ctx := context.Background() //nolint:ineffassign,staticcheck - argocd, dexURL := getTestServer(t, testDataCopy.anonymousEnabled, true) - testDataCopy.claims.Issuer = fmt.Sprintf("%s/api/dex", dexURL) + argocd, oidcURL := getTestServer(t, testDataCopy.anonymousEnabled, true, testDataCopy.useDex, settings_util.OIDCConfig{}) + + if testDataCopy.useDex { + testDataCopy.claims.Issuer = fmt.Sprintf("%s/api/dex", oidcURL) + } else { + testDataCopy.claims.Issuer = oidcURL + } token := jwt.NewWithClaims(jwt.SigningMethodHS256, testDataCopy.claims) tokenString, err := token.SignedString([]byte("key")) require.NoError(t, err) @@ -676,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) + argocd, _ := getTestServer(t, testDataCopy.anonymousEnabled, true, true, settings_util.OIDCConfig{}) ctx := context.Background() ctx, err := argocd.Authenticate(ctx) @@ -722,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) + 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) @@ -795,7 +999,7 @@ func TestAuthenticate_bad_request_metadata(t *testing.T) { test: "anonymous disabled, bad auth header", anonymousEnabled: false, metadata: metadata.MD{"authorization": []string{"Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.TGGTTHuuGpEU8WgobXxkrBtW3NiR3dgw5LR-1DEW3BQ"}}, - expectedErrorMessage: "no audience found in the token", + expectedErrorMessage: common.TokenVerificationError, expectedClaims: nil, }, { @@ -809,7 +1013,7 @@ func TestAuthenticate_bad_request_metadata(t *testing.T) { test: "anonymous disabled, bad auth cookie", anonymousEnabled: false, metadata: metadata.MD{"grpcgateway-cookie": []string{"argocd.token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiJ9.TGGTTHuuGpEU8WgobXxkrBtW3NiR3dgw5LR-1DEW3BQ"}}, - expectedErrorMessage: "no audience found in the token", + expectedErrorMessage: common.TokenVerificationError, expectedClaims: nil, }, { @@ -830,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) + argocd, _ := getTestServer(t, testDataCopy.anonymousEnabled, true, true, settings_util.OIDCConfig{}) ctx = metadata.NewIncomingContext(context.Background(), testDataCopy.metadata) ctx, err := argocd.Authenticate(ctx) @@ -1137,6 +1341,72 @@ func TestIsMainJsBundle(t *testing.T) { } } +func TestCacheControlHeaders(t *testing.T) { + testCases := []struct { + name string + filename string + createFile bool + expectedStatus int + expectedCacheControlHeaders []string + }{ + { + name: "file exists", + filename: "exists.html", + createFile: true, + expectedStatus: 200, + expectedCacheControlHeaders: nil, + }, + { + name: "file does not exist", + filename: "missing.html", + createFile: false, + expectedStatus: 404, + expectedCacheControlHeaders: nil, + }, + { + name: "main js bundle exists", + filename: "main.e4188e5adc97bbfc00c3.js", + createFile: true, + expectedStatus: 200, + expectedCacheControlHeaders: []string{"public, max-age=31536000, immutable"}, + }, + { + name: "main js bundle does not exists", + filename: "main.e4188e5adc97bbfc00c0.js", + createFile: false, + expectedStatus: 404, + expectedCacheControlHeaders: []string{"no-cache"}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + argocd, closer := fakeServer(t) + defer closer() + + handler := argocd.newStaticAssetsHandler() + + rr := httptest.NewRecorder() + req := httptest.NewRequest("", fmt.Sprintf("/%s", testCase.filename), nil) + + fp := filepath.Join(argocd.TmpAssetsDir, testCase.filename) + + if testCase.createFile { + tmpFile, err := os.Create(fp) + assert.NoError(t, err) + err = tmpFile.Close() + assert.NoError(t, err) + } + + handler(rr, req) + + assert.Equal(t, testCase.expectedStatus, rr.Code) + + cacheControl := rr.Result().Header["Cache-Control"] + assert.Equal(t, testCase.expectedCacheControlHeaders, cacheControl) + }) + } +} func TestReplaceBaseHRef(t *testing.T) { testCases := []struct { name string @@ -1162,7 +1432,7 @@ func TestReplaceBaseHRef(t *testing.T) { @@ -1186,7 +1456,7 @@ func TestReplaceBaseHRef(t *testing.T) { @@ -1214,7 +1484,7 @@ func TestReplaceBaseHRef(t *testing.T) { @@ -1238,7 +1508,7 @@ func TestReplaceBaseHRef(t *testing.T) { @@ -1256,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 ba8a582e58cdd..32f5016419b4b 100644 --- a/server/settings/settings.go +++ b/server/settings/settings.go @@ -4,11 +4,11 @@ import ( "context" "fmt" - "github.com/argoproj/argo-cd/v2/reposerver/apiclient" - ioutil "github.com/argoproj/argo-cd/v2/util/io" "github.com/golang/protobuf/ptypes/empty" + "sigs.k8s.io/yaml" - "github.com/ghodss/yaml" + "github.com/argoproj/argo-cd/v2/reposerver/apiclient" + ioutil "github.com/argoproj/argo-cd/v2/util/io" sessionmgr "github.com/argoproj/argo-cd/v2/util/session" @@ -62,10 +62,6 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin if err != nil { return nil, err } - plugins, err := s.plugins(ctx) - if err != nil { - return nil, err - } userLoginsDisabled := true accounts, err := s.mgr.GetAccounts() if err != nil { @@ -110,7 +106,6 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin ChatText: help.ChatText, BinaryUrls: help.BinaryURLs, }, - Plugins: plugins, UserLoginsDisabled: userLoginsDisabled, KustomizeVersions: kustomizeVersions, UiCssURL: argoCDSettings.UiCssURL, @@ -121,15 +116,6 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin } if sessionmgr.LoggedIn(ctx) || s.disableAuth { - configManagementPlugins, err := s.mgr.GetConfigManagementPlugins() - if err != nil { - return nil, err - } - tools := make([]*v1alpha1.ConfigManagementPlugin, len(configManagementPlugins)) - for i := range configManagementPlugins { - tools[i] = &configManagementPlugins[i] - } - set.ConfigManagementPlugins = tools set.UiBannerContent = argoCDSettings.UiBannerContent set.UiBannerURL = argoCDSettings.UiBannerURL set.UiBannerPermanent = argoCDSettings.UiBannerPermanent @@ -145,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 @@ -158,11 +145,16 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin return &set, nil } -func (s *Server) plugins(ctx context.Context) ([]*settingspkg.Plugin, error) { - in, err := s.mgr.GetConfigManagementPlugins() +// GetPlugins returns a list of plugins +func (s *Server) GetPlugins(ctx context.Context, q *settingspkg.SettingsQuery) (*settingspkg.SettingsPluginsResponse, error) { + plugins, err := s.plugins(ctx) if err != nil { return nil, err } + return &settingspkg.SettingsPluginsResponse{Plugins: plugins}, nil +} + +func (s *Server) plugins(ctx context.Context) ([]*settingspkg.Plugin, error) { closer, client, err := s.repoClient.NewRepoServerClient() if err != nil { return nil, fmt.Errorf("error creating repo server client: %w", err) @@ -173,11 +165,8 @@ func (s *Server) plugins(ctx context.Context) ([]*settingspkg.Plugin, error) { if err != nil { return nil, fmt.Errorf("failed to list sidecar plugins from reposerver: %w", err) } - out := []*settingspkg.Plugin{} - for _, p := range in { - out = append(out, &settingspkg.Plugin{Name: p.Name}) - } + var out []*settingspkg.Plugin if pluginList != nil && len(pluginList.Items) > 0 { for _, p := range pluginList.Items { out = append(out, &settingspkg.Plugin{Name: p.Name}) @@ -189,7 +178,11 @@ func (s *Server) plugins(ctx context.Context) ([]*settingspkg.Plugin, error) { // AuthFuncOverride disables authentication for settings service func (s *Server) AuthFuncOverride(ctx context.Context, fullMethodName string) (context.Context, error) { - // this authenticates the user, but ignores any error, so that we have claims populated - ctx, _ = s.authenticator.Authenticate(ctx) - return ctx, nil + ctx, err := s.authenticator.Authenticate(ctx) + if fullMethodName == "/cluster.SettingsService/Get" { + // SettingsService/Get API is used by login page. + // This authenticates the user, but ignores any error, so that we have claims populated + err = nil + } + return ctx, err } diff --git a/server/settings/settings.proto b/server/settings/settings.proto index 0e9ab9951ae30..a6aa97120c8de 100644 --- a/server/settings/settings.proto +++ b/server/settings/settings.proto @@ -28,6 +28,7 @@ message Settings { Help help = 9; repeated Plugin plugins = 10; bool userLoginsDisabled = 11; + // Deprecated: use sidecar plugins instead. repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ConfigManagementPlugin configManagementPlugins = 12; repeated string kustomizeVersions = 13; string uiCssURL = 14; @@ -48,6 +49,10 @@ message GoogleAnalyticsConfig { bool anonymizeUsers = 2; } +message SettingsPluginsResponse { + repeated Plugin plugins = 1; +} + // Help settings message Help { // the URL for getting chat help, this will typically be your Slack channel for support @@ -64,7 +69,6 @@ message Plugin { string name = 1; } - message DexConfig { repeated Connector connectors = 1; } @@ -81,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 @@ -88,7 +93,11 @@ service SettingsService { // Get returns Argo CD settings rpc Get(SettingsQuery) returns (Settings) { - option (google.api.http).get = "/api/v1/settings"; - } + option (google.api.http).get = "/api/v1/settings"; + } + // Get returns Argo CD plugins + rpc GetPlugins(SettingsQuery) returns (SettingsPluginsResponse) { + option (google.api.http).get = "/api/v1/settings/plugins"; + } } diff --git a/server/version/version.go b/server/version/version.go index e899a7ab590d5..cc4eeb24152a6 100644 --- a/server/version/version.go +++ b/server/version/version.go @@ -2,6 +2,7 @@ package version import ( "context" + "github.com/golang/protobuf/ptypes/empty" "github.com/google/go-jsonnet" @@ -67,6 +68,7 @@ func (s *Server) Version(ctx context.Context, _ *empty.Empty) (*version.VersionM HelmVersion: s.helmVersion, JsonnetVersion: s.jsonnetVersion, KubectlVersion: vers.KubectlVersion, + ExtraBuildInfo: vers.ExtraBuildInfo, }, nil } diff --git a/server/version/version.proto b/server/version/version.proto index a2bc1d685661f..f5b887aa29f00 100644 --- a/server/version/version.proto +++ b/server/version/version.proto @@ -23,6 +23,7 @@ message VersionMessage { string HelmVersion = 11; string KubectlVersion = 12; string JsonnetVersion = 13; + string ExtraBuildInfo = 14; } // VersionService returns the version of the API server. diff --git a/test/certificates/ssh_known_hosts b/test/certificates/ssh_known_hosts index 31a7bae3fce5d..0dbb98bd2cacb 100644 --- a/test/certificates/ssh_known_hosts +++ b/test/certificates/ssh_known_hosts @@ -1,6 +1,6 @@ # This file was automatically generated. DO NOT EDIT -bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== -github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== +bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M= +github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9 diff --git a/test/cmp/plugin.yaml b/test/cmp/plugin.yaml index e68fc3dee74af..bc4a3ac8ad57d 100644 --- a/test/cmp/plugin.yaml +++ b/test/cmp/plugin.yaml @@ -4,6 +4,8 @@ metadata: name: cmp-plugin spec: version: v1.0 + init: + command: [env] generate: command: [sh, -c, 'kustomize build'] discover: diff --git a/test/container/Dockerfile b/test/container/Dockerfile index dbb5cb719dc1a..5272b7a14f7d8 100644 --- a/test/container/Dockerfile +++ b/test/container/Dockerfile @@ -1,40 +1,41 @@ -FROM docker.io/library/redis:7.0.5 as redis +FROM docker.io/library/redis:7.2.4@sha256:7dd707032d90c6eaafd566f62a00f5b0116ae08fd7d6cbbb0f311b82b47171a2 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 # architecture, so we create a symlink here to facilitate copying. -RUN ln -s /usr/lib/$(uname -m)-linux-gnu /usr/lib/linux-gnu +RUN ln -s /usr/lib/$(uname -m)-linux-gnu /usr/lib/linux-gnu -FROM docker.io/library/node:12.18.4-buster as node +# 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:21.7.1@sha256:b9ccc4aca32eebf124e0ca0fd573dacffba2b9236987a1d4d2625ce3c162ecc8 as node -FROM docker.io/library/golang:1.18 as golang +FROM docker.io/library/golang:1.21.8@sha256:856073656d1a517517792e6cdd2f7a5ef080d3ca2dff33e518c8412f140fdd2d as golang -FROM docker.io/library/registry:2.8 as registry +FROM docker.io/library/registry:2.8@sha256:fb9c9aef62af3955f6014613456551c92e88a67dcf1fc51f5f91bcbd1832813f as registry -FROM docker.io/bitnami/kubectl:1.23.6 as kubectl +FROM docker.io/bitnami/kubectl:1.27@sha256:14ab746e857d96c105df4989cc2bf841292f2d143f7c60f9d7f549ae660eab43 as kubectl -FROM ubuntu:22.04 +FROM docker.io/library/ubuntu:22.04@sha256:77906da86b60585ce12215807090eb327e7386c8fafb5402369e421f44eff17e ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install --fix-missing -y \ - ca-certificates \ - curl \ - openssh-server \ - nginx \ - fcgiwrap \ - git \ - git-lfs \ - gpg \ - jq \ - make \ - wget \ - gcc \ - g++ \ - sudo \ - tini \ - zip && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + ca-certificates \ + curl \ + openssh-server \ + nginx \ + fcgiwrap \ + git \ + git-lfs \ + gpg \ + jq \ + make \ + wget \ + gcc \ + g++ \ + sudo \ + tini \ + zip && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* COPY --from=golang /usr/local/go /usr/local/go @@ -48,7 +49,7 @@ ENV GOPATH /go COPY hack/install.sh hack/tool-versions.sh go.* ./ COPY hack/installers installers -RUN ./install.sh helm-linux && \ +RUN ./install.sh helm && \ ./install.sh kustomize && \ ./install.sh codegen-tools && \ ./install.sh codegen-go-tools && \ @@ -71,10 +72,10 @@ COPY --from=redis /usr/local/bin/* /usr/local/bin/ # Copy redis dependencies/shared libraries # Ubuntu 22.04+ has moved to OpenSSL3 and no longer provides these libraries -COPY --from=redis /usr/lib/linux-gnu/libssl.so.1.1 /usr/lib/linux-gnu/ -COPY --from=redis /usr/lib/linux-gnu/libcrypto.so.1.1 /usr/lib/linux-gnu/ -RUN mv /usr/lib/linux-gnu/libssl.so.1.1 /usr/lib/$(uname -m)-linux-gnu/ && \ - mv /usr/lib/linux-gnu/libcrypto.so.1.1 /usr/lib/$(uname -m)-linux-gnu/ && \ +COPY --from=redis /usr/lib/linux-gnu/libssl.so.3 /usr/lib/linux-gnu/ +COPY --from=redis /usr/lib/linux-gnu/libcrypto.so.3 /usr/lib/linux-gnu/ +RUN mv /usr/lib/linux-gnu/libssl.so.3 /usr/lib/$(uname -m)-linux-gnu/ && \ + mv /usr/lib/linux-gnu/libcrypto.so.3 /usr/lib/$(uname -m)-linux-gnu/ && \ rm -rf /usr/lib/linux-gnu/ # Copy registry binaries to the image @@ -84,7 +85,7 @@ COPY --from=registry /etc/docker/registry/config.yml /etc/docker/registry/config # Copy node binaries COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules COPY --from=node /usr/local/bin/node /usr/local/bin -COPY --from=node /opt/yarn-v1.22.4 /opt/yarn-v1.22.4 +COPY --from=node /opt/yarn-v1.22.19 /opt/yarn-v1.22.19 # Entrypoint is required for container's user management COPY ./test/container/entrypoint.sh /usr/local/bin @@ -95,6 +96,7 @@ ARG UID RUN useradd -l -u ${UID} -d /home/user -s /bin/bash user && \ echo "user ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/user && \ mkdir -p /home/user/.kube && \ + mkdir -p /home/user/.cache && \ chown -R user /home/user && \ chgrp -R user /home/user && \ HOME=/home/user git config --global user.name "ArgoCD Test User" && \ @@ -106,12 +108,11 @@ RUN useradd -l -u ${UID} -d /home/user -s /bin/bash user && \ chown root /etc/ssh/ssh_host_*_key* && \ chmod 0600 /etc/ssh/ssh_host_*_key && \ mkdir -p /tmp/go-build-cache && \ - mkdir -p /home/user/.cache && \ ln -s /usr/local/bin/node /usr/local/bin/nodejs && \ ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \ ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx && \ - ln -s /opt/yarn-v1.22.4/bin/yarn /usr/local/bin/yarn && \ - ln -s /opt/yarn-v1.22.4/bin/yarnpkg /usr/local/bin/yarnpkg && \ + ln -s /opt/yarn-v1.22.19/bin/yarn /usr/local/bin/yarn && \ + ln -s /opt/yarn-v1.22.19/bin/yarnpkg /usr/local/bin/yarnpkg && \ mkdir -p /var/lib/registry ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/test/container/Procfile b/test/container/Procfile index bc03df97bd53a..3ec9add44d5a7 100644 --- a/test/container/Procfile +++ b/test/container/Procfile @@ -1,8 +1,8 @@ -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.30.0 serve /dex.yaml" +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.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}" +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" reaper: ./test/container/reaper.sh sshd: sudo sh -c "test $ARGOCD_E2E_TEST = true && /usr/sbin/sshd -p 2222 -D -e" @@ -10,5 +10,5 @@ fcgiwrap: sudo sh -c "test $ARGOCD_E2E_TEST = true && (fcgiwrap -s unix:/var/run nginx: sudo sh -c "test $ARGOCD_E2E_TEST = true && nginx -g 'daemon off;' -c $(pwd)/test/fixture/testrepos/nginx.conf" helm-registry: sudo sh -c "registry serve /etc/docker/registry/config.yml" dev-mounter: test "$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_ASK_PASS_SOCK=/tmp/applicationset-ask-pass.sock 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}" +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: 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 go run ./cmd/main.go --loglevel debug" diff --git a/test/e2e/accounts_test.go b/test/e2e/accounts_test.go index f794dce7a56e9..54eba790af2c5 100644 --- a/test/e2e/accounts_test.go +++ b/test/e2e/accounts_test.go @@ -14,7 +14,6 @@ import ( "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/headless" "github.com/argoproj/argo-cd/v2/pkg/apiclient/account" "github.com/argoproj/argo-cd/v2/pkg/apiclient/session" - "github.com/argoproj/argo-cd/v2/test/e2e/fixture" . "github.com/argoproj/argo-cd/v2/test/e2e/fixture" accountFixture "github.com/argoproj/argo-cd/v2/test/e2e/fixture/account" "github.com/argoproj/argo-cd/v2/util/io" @@ -77,7 +76,7 @@ func TestCanIGetLogsAllowSwitchOn(t *testing.T) { When(). Create(). Login(). - SetPermissions([]fixture.ACL{ + SetPermissions([]ACL{ { Resource: "logs", Action: "get", diff --git a/test/e2e/api_versions_test.go b/test/e2e/api_versions_test.go new file mode 100644 index 0000000000000..9ef2ba01561d6 --- /dev/null +++ b/test/e2e/api_versions_test.go @@ -0,0 +1,57 @@ +package e2e + +import ( + "testing" + + . "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + . "github.com/argoproj/argo-cd/v2/test/e2e/fixture/app" +) + +func TestAppSyncWrongVersion(t *testing.T) { + // Make sure the error messages are good when there are group or version mismatches between CRDs and resources. + ctx := Given(t) + ctx. + Path("crd-version-differences"). + When(). + CreateApp(). + // Install CRD and one instance of it on v1alpha1 + AppSet("--directory-include", "crd-v1alpha1.yaml"). + Sync(). + Then(). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + When(). + AppSet("--directory-include", "crd-v1alpha2-instance.yaml"). + IgnoreErrors(). // Ignore errors because we are testing the error message. + Sync(). + Then(). + Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). + When(). + DoNotIgnoreErrors(). + Get(). + Then(). + // Technically it's a "success" because we're just doing a "get," but the get output contains the error message. + Expect(SuccessRegex(`The Kubernetes API could not find version "v1alpha2" of argoproj\.io/Fake for requested resource [a-z0-9-]+/fake-crd-instance\. Version "v1alpha1" of argoproj\.io/Fake is installed on the destination cluster\.`)). + When(). + AppSet("--directory-include", "crd-wronggroup-instance.yaml", "--directory-exclude", "crd-v1alpha2-instance.yaml"). + IgnoreErrors(). // Ignore errors because we are testing the error message. + Sync(). + Then(). + Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). + When(). + DoNotIgnoreErrors(). + Get(). + Then(). + Expect(SuccessRegex(`The Kubernetes API could not find version "v1alpha1" of wrong\.group/Fake for requested resource [a-z0-9-]+/fake-crd-instance-wronggroup\. Version "v1alpha1" of argoproj\.io/Fake is installed on the destination cluster\.`)). + When(). + AppSet("--directory-include", "crd-does-not-exist-instance.yaml", "--directory-exclude", "crd-wronggroup-instance.yaml"). + IgnoreErrors(). // Ignore errors because we are testing the error message. + Sync(). + Then(). + Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). + When(). + DoNotIgnoreErrors(). + Get(). + Then(). + // Not the best error message, but good enough. + Expect(Success(`DoesNotExist.argoproj.io "" not found`)) +} diff --git a/test/e2e/app_deletion_test.go b/test/e2e/app_deletion_test.go index 1194edcb37df3..9158dddffa06a 100644 --- a/test/e2e/app_deletion_test.go +++ b/test/e2e/app_deletion_test.go @@ -67,3 +67,18 @@ func TestDeletingAppByLabel(t *testing.T) { // delete is successful Expect(DoesNotExist()) } + +func TestDeletingAppByLabelWait(t *testing.T) { + Given(t). + Path(guestbookPath). + When(). + CreateApp("--label=foo=bar"). + Sync(). + Then(). + Expect(SyncStatusIs(SyncStatusCode(SyncStatusCodeSynced))). + When(). + DeleteBySelectorWithWait("foo=bar"). + Then(). + // delete is successful + Expect(DoesNotExistNow()) +} diff --git a/test/e2e/app_management_ns_test.go b/test/e2e/app_management_ns_test.go index f9f3a71282644..32636e2b52c49 100644 --- a/test/e2e/app_management_ns_test.go +++ b/test/e2e/app_management_ns_test.go @@ -36,6 +36,7 @@ import ( repoFixture "github.com/argoproj/argo-cd/v2/test/e2e/fixture/repos" "github.com/argoproj/argo-cd/v2/test/e2e/testdata" + "github.com/argoproj/argo-cd/v2/pkg/apis/application" . "github.com/argoproj/argo-cd/v2/util/argo" . "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/io" @@ -89,7 +90,7 @@ func TestNamespacedGetLogsDenySwitchOn(t *testing.T) { Then(). Expect(HealthIs(health.HealthStatusHealthy)). And(func(app *Application) { - _, err := RunCli("app", "logs", ctx.AppQualifiedName(), "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") + _, err := RunCliWithRetry(5, "app", "logs", ctx.AppQualifiedName(), "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") assert.Error(t, err) assert.Contains(t, err.Error(), "permission denied") }) @@ -143,17 +144,17 @@ func TestNamespacedGetLogsAllowSwitchOnNS(t *testing.T) { Then(). Expect(HealthIs(health.HealthStatusHealthy)). And(func(app *Application) { - out, err := RunCli("app", "logs", ctx.AppQualifiedName(), "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") + out, err := RunCliWithRetry(5, "app", "logs", ctx.AppQualifiedName(), "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", ctx.AppQualifiedName(), "--kind", "Pod") + out, err := RunCliWithRetry(5, "app", "logs", ctx.AppQualifiedName(), "--kind", "Pod") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", ctx.AppQualifiedName(), "--kind", "Service") + out, err := RunCliWithRetry(5, "app", "logs", ctx.AppQualifiedName(), "--kind", "Service") assert.NoError(t, err) assert.NotContains(t, out, "Hi") }) @@ -202,17 +203,17 @@ func TestNamespacedGetLogsAllowSwitchOff(t *testing.T) { Then(). Expect(HealthIs(health.HealthStatusHealthy)). And(func(app *Application) { - out, err := RunCli("app", "logs", ctx.AppQualifiedName(), "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") + out, err := RunCliWithRetry(5, "app", "logs", ctx.AppQualifiedName(), "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", ctx.AppQualifiedName(), "--kind", "Pod") + out, err := RunCliWithRetry(5, "app", "logs", ctx.AppQualifiedName(), "--kind", "Pod") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", ctx.AppQualifiedName(), "--kind", "Service") + out, err := RunCliWithRetry(5, "app", "logs", ctx.AppQualifiedName(), "--kind", "Service") assert.NoError(t, err) assert.NotContains(t, out, "Hi") }) @@ -429,7 +430,9 @@ func TestNamespacedInvalidAppProject(t *testing.T) { IgnoreErrors(). CreateApp(). Then(). - Expect(Error("", "application references project does-not-exist which does not exist")) + // We're not allowed to infer whether the project exists based on this error message. Instead, we get a generic + // permission denied error. + Expect(Error("", "permission denied")) } func TestNamespacedAppDeletion(t *testing.T) { @@ -745,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())) }). @@ -758,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) }). @@ -834,7 +837,7 @@ func TestNamespacedResourceDiffing(t *testing.T) { // } func TestNamespacedKnownTypesInCRDDiffing(t *testing.T) { - dummiesGVR := schema.GroupVersionResource{Group: "argoproj.io", Version: "v1alpha1", Resource: "dummies"} + dummiesGVR := schema.GroupVersionResource{Group: application.Group, Version: "v1alpha1", Resource: "dummies"} ctx := Given(t) ctx. @@ -894,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) }) @@ -995,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) { @@ -1063,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() @@ -1176,7 +1179,7 @@ func TestNamespacedPermissions(t *testing.T) { Create() sourceError := fmt.Sprintf("application repo %s is not permitted in project 'argo-project'", RepoURL(RepoURLTypeFile)) - destinationError := fmt.Sprintf("application destination {%s %s} is not permitted in project 'argo-project'", KubernetesInternalAPIServerAddr, DeploymentNamespace()) + destinationError := fmt.Sprintf("application destination server '%s' and namespace '%s' do not match any of the allowed destinations in project 'argo-project'", KubernetesInternalAPIServerAddr, DeploymentNamespace()) appCtx. Path("guestbook-logs"). @@ -1480,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"). @@ -1512,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(). @@ -1528,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(). @@ -1545,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(). @@ -1603,15 +1606,15 @@ func TestNamespacedNotPermittedResources(t *testing.T) { }, } defer func() { - log.Infof("Ingress 'sample-ingress' deleted from %s", ArgoCDNamespace) - CheckError(KubeClientset.NetworkingV1().Ingresses(ArgoCDNamespace).Delete(context.Background(), "sample-ingress", metav1.DeleteOptions{})) + log.Infof("Ingress 'sample-ingress' deleted from %s", TestNamespace()) + CheckError(KubeClientset.NetworkingV1().Ingresses(TestNamespace()).Delete(context.Background(), "sample-ingress", metav1.DeleteOptions{})) }() svc := &v1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: "guestbook-ui", Annotations: map[string]string{ - common.AnnotationKeyAppInstance: fmt.Sprintf("%s_%s:Service:%s/guesbook-ui", ArgoCDNamespace, ctx.AppQualifiedName(), DeploymentNamespace()), + common.AnnotationKeyAppInstance: fmt.Sprintf("%s_%s:Service:%s/guesbook-ui", TestNamespace(), ctx.AppQualifiedName(), DeploymentNamespace()), }, }, Spec: v1.ServiceSpec{ @@ -1633,7 +1636,7 @@ func TestNamespacedNotPermittedResources(t *testing.T) { {Group: "", Kind: "Service"}, }}). And(func() { - FailOnErr(KubeClientset.NetworkingV1().Ingresses(ArgoCDNamespace).Create(context.Background(), ingress, metav1.CreateOptions{})) + FailOnErr(KubeClientset.NetworkingV1().Ingresses(TestNamespace()).Create(context.Background(), ingress, metav1.CreateOptions{})) FailOnErr(KubeClientset.CoreV1().Services(DeploymentNamespace()).Create(context.Background(), svc, metav1.CreateOptions{})) }). Path(guestbookPath). @@ -1659,7 +1662,7 @@ func TestNamespacedNotPermittedResources(t *testing.T) { Expect(DoesNotExist()) // Make sure prohibited resources are not deleted during application deletion - FailOnErr(KubeClientset.NetworkingV1().Ingresses(ArgoCDNamespace).Get(context.Background(), "sample-ingress", metav1.GetOptions{})) + FailOnErr(KubeClientset.NetworkingV1().Ingresses(TestNamespace()).Get(context.Background(), "sample-ingress", metav1.GetOptions{})) FailOnErr(KubeClientset.CoreV1().Services(DeploymentNamespace()).Get(context.Background(), "guestbook-ui", metav1.GetOptions{})) } @@ -1767,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). @@ -1860,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) @@ -2086,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() { @@ -2106,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) })). @@ -2127,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) })). @@ -2306,17 +2309,17 @@ func TestNamespacedAppLogs(t *testing.T) { Then(). Expect(HealthIs(health.HealthStatusHealthy)). And(func(app *Application) { - out, err := RunCli("app", "logs", app.QualifiedName(), "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") + out, err := RunCliWithRetry(5, "app", "logs", app.QualifiedName(), "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", app.QualifiedName(), "--kind", "Pod") + out, err := RunCliWithRetry(5, "app", "logs", app.QualifiedName(), "--kind", "Pod") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", app.QualifiedName(), "--kind", "Service") + out, err := RunCliWithRetry(5, "app", "logs", app.QualifiedName(), "--kind", "Service") assert.NoError(t, err) assert.NotContains(t, out, "Hi") }) @@ -2445,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 a1152d0f6495b..10b2cf926723c 100644 --- a/test/e2e/app_management_test.go +++ b/test/e2e/app_management_test.go @@ -41,6 +41,8 @@ import ( . "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/io" "github.com/argoproj/argo-cd/v2/util/settings" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application" ) const ( @@ -48,6 +50,8 @@ const ( guestbookPathLocal = "./testdata/guestbook_local" globalWithNoNameSpace = "global-with-no-namespace" guestbookWithNamespace = "guestbook-with-namespace" + resourceActions = "resource-actions" + appLogsRetryCount = 5 ) // This empty test is here only for clarity, to conform to logs rbac tests structure in account. This exact usecase is covered in the TestAppLogs test @@ -94,7 +98,7 @@ func TestGetLogsDenySwitchOn(t *testing.T) { Then(). Expect(HealthIs(health.HealthStatusHealthy)). And(func(app *Application) { - _, err := RunCli("app", "logs", app.Name, "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") + _, err := RunCliWithRetry(appLogsRetryCount, "app", "logs", app.Name, "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") assert.Error(t, err) assert.Contains(t, err.Error(), "permission denied") }) @@ -145,17 +149,17 @@ func TestGetLogsAllowSwitchOn(t *testing.T) { Then(). Expect(HealthIs(health.HealthStatusHealthy)). And(func(app *Application) { - out, err := RunCli("app", "logs", app.Name, "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") + out, err := RunCliWithRetry(appLogsRetryCount, "app", "logs", app.Name, "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", app.Name, "--kind", "Pod") + out, err := RunCliWithRetry(appLogsRetryCount, "app", "logs", app.Name, "--kind", "Pod") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", app.Name, "--kind", "Service") + out, err := RunCliWithRetry(appLogsRetryCount, "app", "logs", app.Name, "--kind", "Service") assert.NoError(t, err) assert.NotContains(t, out, "Hi") }) @@ -202,17 +206,17 @@ func TestGetLogsAllowSwitchOff(t *testing.T) { Then(). Expect(HealthIs(health.HealthStatusHealthy)). And(func(app *Application) { - out, err := RunCli("app", "logs", app.Name, "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") + out, err := RunCliWithRetry(appLogsRetryCount, "app", "logs", app.Name, "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", app.Name, "--kind", "Pod") + out, err := RunCliWithRetry(appLogsRetryCount, "app", "logs", app.Name, "--kind", "Pod") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", app.Name, "--kind", "Service") + out, err := RunCliWithRetry(appLogsRetryCount, "app", "logs", app.Name, "--kind", "Service") assert.NoError(t, err) assert.NotContains(t, out, "Hi") }) @@ -249,11 +253,30 @@ func TestSyncToSignedCommitWithoutKnownKey(t *testing.T) { Expect(HealthIs(health.HealthStatusMissing)) } -func TestSyncToSignedCommitKeyWithKnownKey(t *testing.T) { +func TestSyncToSignedCommitWithKnownKey(t *testing.T) { + SkipOnEnv(t, "GPG") + Given(t). + Project("gpg"). + Path(guestbookPath). + GPGPublicKeyAdded(). + Sleep(2). + When(). + AddSignedFile("test.yaml", "null"). + IgnoreErrors(). + CreateApp(). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(HealthIs(health.HealthStatusHealthy)) +} + +func TestSyncToSignedBranchWithKnownKey(t *testing.T) { SkipOnEnv(t, "GPG") Given(t). Project("gpg"). Path(guestbookPath). + Revision("master"). GPGPublicKeyAdded(). Sleep(2). When(). @@ -267,6 +290,98 @@ func TestSyncToSignedCommitKeyWithKnownKey(t *testing.T) { Expect(HealthIs(health.HealthStatusHealthy)) } +func TestSyncToSignedBranchWithUnknownKey(t *testing.T) { + SkipOnEnv(t, "GPG") + Given(t). + Project("gpg"). + Path(guestbookPath). + Revision("master"). + Sleep(2). + When(). + AddSignedFile("test.yaml", "null"). + IgnoreErrors(). + CreateApp(). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationError)). + Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). + Expect(HealthIs(health.HealthStatusMissing)) +} + +func TestSyncToUnsignedBranch(t *testing.T) { + SkipOnEnv(t, "GPG") + Given(t). + Project("gpg"). + Revision("master"). + Path(guestbookPath). + GPGPublicKeyAdded(). + Sleep(2). + When(). + IgnoreErrors(). + CreateApp(). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationError)). + Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). + Expect(HealthIs(health.HealthStatusMissing)) +} + +func TestSyncToSignedTagWithKnownKey(t *testing.T) { + SkipOnEnv(t, "GPG") + Given(t). + Project("gpg"). + Revision("signed-tag"). + Path(guestbookPath). + GPGPublicKeyAdded(). + Sleep(2). + When(). + AddSignedTag("signed-tag"). + IgnoreErrors(). + CreateApp(). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(HealthIs(health.HealthStatusHealthy)) +} + +func TestSyncToSignedTagWithUnknownKey(t *testing.T) { + SkipOnEnv(t, "GPG") + Given(t). + Project("gpg"). + Revision("signed-tag"). + Path(guestbookPath). + Sleep(2). + When(). + AddSignedTag("signed-tag"). + IgnoreErrors(). + CreateApp(). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationError)). + Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). + Expect(HealthIs(health.HealthStatusMissing)) +} + +func TestSyncToUnsignedTag(t *testing.T) { + SkipOnEnv(t, "GPG") + Given(t). + Project("gpg"). + Revision("unsigned-tag"). + Path(guestbookPath). + GPGPublicKeyAdded(). + Sleep(2). + When(). + AddTag("unsigned-tag"). + IgnoreErrors(). + CreateApp(). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationError)). + Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). + Expect(HealthIs(health.HealthStatusMissing)) +} + func TestAppCreation(t *testing.T) { ctx := Given(t) ctx. @@ -298,7 +413,7 @@ func TestAppCreation(t *testing.T) { When(). // ensure that update replaces spec and merge labels and annotations And(func() { - FailOnErr(AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Patch(context.Background(), + FailOnErr(AppClientset.ArgoprojV1alpha1().Applications(TestNamespace()).Patch(context.Background(), ctx.GetName(), types.MergePatchType, []byte(`{"metadata": {"labels": { "test": "label" }, "annotations": { "test": "annotation" }}}`), metav1.PatchOptions{})) }). CreateApp("--upsert"). @@ -361,6 +476,24 @@ func TestDeleteAppResource(t *testing.T) { Expect(HealthIs(health.HealthStatusMissing)) } +// Fix for issue #2677, support PATCH in HTTP service +func TestPatchHttp(t *testing.T) { + ctx := Given(t) + + ctx. + Path(guestbookPath). + When(). + CreateApp(). + Sync(). + PatchAppHttp(`{"metadata": {"labels": { "test": "patch" }, "annotations": { "test": "patch" }}}`). + Then(). + And(func(app *Application) { + assert.Equal(t, "patch", app.Labels["test"]) + assert.Equal(t, "patch", app.Annotations["test"]) + }) + +} + // demonstrate that we cannot use a standard sync when an immutable field is changed, we must use "force" func TestImmutableChange(t *testing.T) { SkipOnEnv(t, "OPENSHIFT") @@ -412,7 +545,9 @@ func TestInvalidAppProject(t *testing.T) { IgnoreErrors(). CreateApp(). Then(). - Expect(Error("", "application references project does-not-exist which does not exist")) + // We're not allowed to infer whether the project exists based on this error message. Instead, we get a generic + // permission denied error. + Expect(Error("", "permission denied")) } func TestAppDeletion(t *testing.T) { @@ -503,7 +638,7 @@ func TestAppRollbackSuccessful(t *testing.T) { }} patch, _, err := diff.CreateTwoWayMergePatch(app, appWithHistory, &Application{}) require.NoError(t, err) - app, err = AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{}) + app, err = AppClientset.ArgoprojV1alpha1().Applications(TestNamespace()).Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{}) require.NoError(t, err) // sync app and make sure it reaches InSync state @@ -812,7 +947,7 @@ func TestCRDs(t *testing.T) { } func TestKnownTypesInCRDDiffing(t *testing.T) { - dummiesGVR := schema.GroupVersionResource{Group: "argoproj.io", Version: "v1alpha1", Resource: "dummies"} + dummiesGVR := schema.GroupVersionResource{Group: application.Group, Version: "v1alpha1", Resource: "dummies"} Given(t). Path("crd-creation"). @@ -878,7 +1013,7 @@ definitions: obj.metadata.labels.sample = 'test' return obj` -func TestResourceAction(t *testing.T) { +func TestOldStyleResourceAction(t *testing.T) { Given(t). Path(guestbookPath). ResourceOverrides(map[string]ResourceOverride{"apps/Deployment": {Actions: actionsConfig}}). @@ -920,6 +1055,224 @@ func TestResourceAction(t *testing.T) { }) } +const newStyleActionsConfig = `discovery.lua: return { sample = {} } +definitions: +- name: sample + action.lua: | + local os = require("os") + + function deepCopy(object) + local lookup_table = {} + local function _copy(obj) + if type(obj) ~= "table" then + return obj + elseif lookup_table[obj] then + return lookup_table[obj] + elseif next(obj) == nil then + return nil + else + local new_table = {} + lookup_table[obj] = new_table + for key, value in pairs(obj) do + new_table[_copy(key)] = _copy(value) + end + return setmetatable(new_table, getmetatable(obj)) + end + end + return _copy(object) + end + + job = {} + job.apiVersion = "batch/v1" + job.kind = "Job" + + job.metadata = {} + job.metadata.name = obj.metadata.name .. "-123" + job.metadata.namespace = obj.metadata.namespace + + ownerRef = {} + ownerRef.apiVersion = obj.apiVersion + ownerRef.kind = obj.kind + ownerRef.name = obj.metadata.name + ownerRef.uid = obj.metadata.uid + job.metadata.ownerReferences = {} + job.metadata.ownerReferences[1] = ownerRef + + job.spec = {} + job.spec.suspend = false + job.spec.template = {} + job.spec.template.spec = deepCopy(obj.spec.jobTemplate.spec.template.spec) + + impactedResource = {} + impactedResource.operation = "create" + impactedResource.resource = job + result = {} + result[1] = impactedResource + + return result` + +func TestNewStyleResourceActionPermitted(t *testing.T) { + Given(t). + Path(resourceActions). + ResourceOverrides(map[string]ResourceOverride{"batch/CronJob": {Actions: newStyleActionsConfig}}). + ProjectSpec(AppProjectSpec{ + SourceRepos: []string{"*"}, + Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, + NamespaceResourceWhitelist: []metav1.GroupKind{ + {Group: "batch", Kind: "Job"}, + {Group: "batch", Kind: "CronJob"}, + }}). + When(). + CreateApp(). + Sync(). + Then(). + And(func(app *Application) { + + closer, client, err := ArgoCDClientset.NewApplicationClient() + assert.NoError(t, err) + defer io.Close(closer) + + actions, err := client.ListResourceActions(context.Background(), &applicationpkg.ApplicationResourceRequest{ + Name: &app.Name, + Group: pointer.String("batch"), + Kind: pointer.String("CronJob"), + Version: pointer.String("v1"), + Namespace: pointer.String(DeploymentNamespace()), + ResourceName: pointer.String("hello"), + }) + assert.NoError(t, err) + assert.Equal(t, []*ResourceAction{{Name: "sample", Disabled: false}}, actions.Actions) + + _, err = client.RunResourceAction(context.Background(), &applicationpkg.ResourceActionRunRequest{Name: &app.Name, + Group: pointer.String("batch"), + Kind: pointer.String("CronJob"), + Version: pointer.String("v1"), + Namespace: pointer.String(DeploymentNamespace()), + ResourceName: pointer.String("hello"), + Action: pointer.String("sample"), + }) + assert.NoError(t, err) + + _, err = KubeClientset.BatchV1().Jobs(DeploymentNamespace()).Get(context.Background(), "hello-123", metav1.GetOptions{}) + assert.NoError(t, err) + }) +} + +const newStyleActionsConfigMixedOk = `discovery.lua: return { sample = {} } +definitions: +- name: sample + action.lua: | + local os = require("os") + + function deepCopy(object) + local lookup_table = {} + local function _copy(obj) + if type(obj) ~= "table" then + return obj + elseif lookup_table[obj] then + return lookup_table[obj] + elseif next(obj) == nil then + return nil + else + local new_table = {} + lookup_table[obj] = new_table + for key, value in pairs(obj) do + new_table[_copy(key)] = _copy(value) + end + return setmetatable(new_table, getmetatable(obj)) + end + end + return _copy(object) + end + + job = {} + job.apiVersion = "batch/v1" + job.kind = "Job" + + job.metadata = {} + job.metadata.name = obj.metadata.name .. "-123" + job.metadata.namespace = obj.metadata.namespace + + ownerRef = {} + ownerRef.apiVersion = obj.apiVersion + ownerRef.kind = obj.kind + ownerRef.name = obj.metadata.name + ownerRef.uid = obj.metadata.uid + job.metadata.ownerReferences = {} + job.metadata.ownerReferences[1] = ownerRef + + job.spec = {} + job.spec.suspend = false + job.spec.template = {} + job.spec.template.spec = deepCopy(obj.spec.jobTemplate.spec.template.spec) + + impactedResource1 = {} + impactedResource1.operation = "create" + impactedResource1.resource = job + result = {} + result[1] = impactedResource1 + + obj.metadata.labels["aKey"] = 'aValue' + impactedResource2 = {} + impactedResource2.operation = "patch" + impactedResource2.resource = obj + + result[2] = impactedResource2 + + return result` + +func TestNewStyleResourceActionMixedOk(t *testing.T) { + Given(t). + Path(resourceActions). + ResourceOverrides(map[string]ResourceOverride{"batch/CronJob": {Actions: newStyleActionsConfigMixedOk}}). + ProjectSpec(AppProjectSpec{ + SourceRepos: []string{"*"}, + Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, + NamespaceResourceWhitelist: []metav1.GroupKind{ + {Group: "batch", Kind: "Job"}, + {Group: "batch", Kind: "CronJob"}, + }}). + When(). + CreateApp(). + Sync(). + Then(). + And(func(app *Application) { + + closer, client, err := ArgoCDClientset.NewApplicationClient() + assert.NoError(t, err) + defer io.Close(closer) + + actions, err := client.ListResourceActions(context.Background(), &applicationpkg.ApplicationResourceRequest{ + Name: &app.Name, + Group: pointer.String("batch"), + Kind: pointer.String("CronJob"), + Version: pointer.String("v1"), + Namespace: pointer.String(DeploymentNamespace()), + ResourceName: pointer.String("hello"), + }) + assert.NoError(t, err) + assert.Equal(t, []*ResourceAction{{Name: "sample", Disabled: false}}, actions.Actions) + + _, err = client.RunResourceAction(context.Background(), &applicationpkg.ResourceActionRunRequest{Name: &app.Name, + Group: pointer.String("batch"), + Kind: pointer.String("CronJob"), + Version: pointer.String("v1"), + Namespace: pointer.String(DeploymentNamespace()), + ResourceName: pointer.String("hello"), + Action: pointer.String("sample"), + }) + assert.NoError(t, err) + + // Assert new Job was created + _, err = KubeClientset.BatchV1().Jobs(DeploymentNamespace()).Get(context.Background(), "hello-123", metav1.GetOptions{}) + assert.NoError(t, err) + // Assert the original CronJob was patched + cronJob, err := KubeClientset.BatchV1().CronJobs(DeploymentNamespace()).Get(context.Background(), "hello", metav1.GetOptions{}) + assert.Equal(t, "aValue", cronJob.Labels["aKey"]) + assert.NoError(t, err) + }) +} + func TestSyncResourceByLabel(t *testing.T) { Given(t). Path(guestbookPath). @@ -971,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) { @@ -1032,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() @@ -1137,7 +1490,7 @@ func TestPermissions(t *testing.T) { Create() sourceError := fmt.Sprintf("application repo %s is not permitted in project 'argo-project'", RepoURL(RepoURLTypeFile)) - destinationError := fmt.Sprintf("application destination {%s %s} is not permitted in project 'argo-project'", KubernetesInternalAPIServerAddr, DeploymentNamespace()) + destinationError := fmt.Sprintf("application destination server '%s' and namespace '%s' do not match any of the allowed destinations in project 'argo-project'", KubernetesInternalAPIServerAddr, DeploymentNamespace()) appCtx. Path("guestbook-logs"). @@ -1179,7 +1532,7 @@ func TestPermissions(t *testing.T) { And(func(app *Application) { closer, cdClient := ArgoCDClientset.NewApplicationClientOrDie() defer io.Close(closer) - appName, appNs := argo.ParseAppQualifiedName(app.Name, "") + appName, appNs := argo.ParseFromQualifiedName(app.Name, "") fmt.Printf("APP NAME: %s\n", appName) tree, err := cdClient.ResourceTree(context.Background(), &applicationpkg.ResourcesQuery{ApplicationName: &appName, AppNamespace: &appNs}) require.NoError(t, err) @@ -1293,7 +1646,7 @@ func TestPermissionDeniedWithNegatedNamespace(t *testing.T) { IgnoreErrors(). CreateApp(). Then(). - Expect(Error("", "is not permitted in project")) + Expect(Error("", "do not match any of the allowed destinations in project")) } func TestPermissionDeniedWithNegatedServer(t *testing.T) { @@ -1320,7 +1673,7 @@ func TestPermissionDeniedWithNegatedServer(t *testing.T) { IgnoreErrors(). CreateApp(). Then(). - Expect(Error("", "is not permitted in project")) + Expect(Error("", "do not match any of the allowed destinations in project")) } // make sure that if we deleted a resource from the app, it is not pruned if annotated with Prune=false @@ -1401,6 +1754,40 @@ func TestCompareOptionIgnoreExtraneous(t *testing.T) { Expect(SyncStatusIs(SyncStatusCodeSynced)) } +func TestSourceNamespaceCanBeMigratedToManagedNamespaceWithoutBeingPrunedOrOutOfSync(t *testing.T) { + Given(t). + Prune(true). + Path("guestbook-with-plain-namespace-manifest"). + When(). + PatchFile("guestbook-ui-namespace.yaml", fmt.Sprintf(`[{"op": "replace", "path": "/metadata/name", "value": "%s"}]`, DeploymentNamespace())). + CreateApp(). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + When(). + PatchApp(`[{ + "op": "add", + "path": "/spec/syncPolicy", + "value": { "prune": true, "syncOptions": ["PrunePropagationPolicy=foreground"], "managedNamespaceMetadata": { "labels": { "foo": "bar" } } } + }]`). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + And(func(app *Application) { + assert.Equal(t, &ManagedNamespaceMetadata{Labels: map[string]string{"foo": "bar"}}, app.Spec.SyncPolicy.ManagedNamespaceMetadata) + }). + When(). + DeleteFile("guestbook-ui-namespace.yaml"). + Refresh(RefreshTypeHard). + Sync(). + Wait(). + Then(). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(SyncStatusIs(SyncStatusCodeSynced)) +} + func TestSelfManagedApps(t *testing.T) { Given(t). @@ -1477,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(). @@ -1506,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). @@ -1521,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). @@ -1537,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). @@ -1593,8 +1980,8 @@ func TestNotPermittedResources(t *testing.T) { }, } defer func() { - log.Infof("Ingress 'sample-ingress' deleted from %s", ArgoCDNamespace) - CheckError(KubeClientset.NetworkingV1().Ingresses(ArgoCDNamespace).Delete(context.Background(), "sample-ingress", metav1.DeleteOptions{})) + log.Infof("Ingress 'sample-ingress' deleted from %s", TestNamespace()) + CheckError(KubeClientset.NetworkingV1().Ingresses(TestNamespace()).Delete(context.Background(), "sample-ingress", metav1.DeleteOptions{})) }() svc := &v1.Service{ @@ -1622,7 +2009,7 @@ func TestNotPermittedResources(t *testing.T) { {Group: "", Kind: "Service"}, }}). And(func() { - FailOnErr(KubeClientset.NetworkingV1().Ingresses(ArgoCDNamespace).Create(context.Background(), ingress, metav1.CreateOptions{})) + FailOnErr(KubeClientset.NetworkingV1().Ingresses(TestNamespace()).Create(context.Background(), ingress, metav1.CreateOptions{})) FailOnErr(KubeClientset.CoreV1().Services(DeploymentNamespace()).Create(context.Background(), svc, metav1.CreateOptions{})) }). Path(guestbookPath). @@ -1648,7 +2035,7 @@ func TestNotPermittedResources(t *testing.T) { Expect(DoesNotExist()) // Make sure prohibited resources are not deleted during application deletion - FailOnErr(KubeClientset.NetworkingV1().Ingresses(ArgoCDNamespace).Get(context.Background(), "sample-ingress", metav1.GetOptions{})) + FailOnErr(KubeClientset.NetworkingV1().Ingresses(TestNamespace()).Get(context.Background(), "sample-ingress", metav1.GetOptions{})) FailOnErr(KubeClientset.CoreV1().Services(DeploymentNamespace()).Get(context.Background(), "guestbook-ui", metav1.GetOptions{})) } @@ -1687,7 +2074,7 @@ func TestCreateAppWithNoNameSpaceForGlobalResource(t *testing.T) { Then(). And(func(app *Application) { time.Sleep(500 * time.Millisecond) - app, err := AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Get(context.Background(), app.Name, metav1.GetOptions{}) + app, err := AppClientset.ArgoprojV1alpha1().Applications(TestNamespace()).Get(context.Background(), app.Name, metav1.GetOptions{}) assert.NoError(t, err) assert.Len(t, app.Status.Conditions, 0) }) @@ -1707,7 +2094,7 @@ func TestCreateAppWithNoNameSpaceWhenRequired(t *testing.T) { Refresh(RefreshTypeNormal). Then(). And(func(app *Application) { - updatedApp, err := AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Get(context.Background(), app.Name, metav1.GetOptions{}) + updatedApp, err := AppClientset.ArgoprojV1alpha1().Applications(TestNamespace()).Get(context.Background(), app.Name, metav1.GetOptions{}) require.NoError(t, err) assert.Len(t, updatedApp.Status.Conditions, 2) @@ -1731,7 +2118,7 @@ func TestCreateAppWithNoNameSpaceWhenRequired2(t *testing.T) { Refresh(RefreshTypeNormal). Then(). And(func(app *Application) { - updatedApp, err := AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Get(context.Background(), app.Name, metav1.GetOptions{}) + updatedApp, err := AppClientset.ArgoprojV1alpha1().Applications(TestNamespace()).Get(context.Background(), app.Name, metav1.GetOptions{}) require.NoError(t, err) assert.Len(t, updatedApp.Status.Conditions, 2) @@ -1746,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(). @@ -1821,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") @@ -1840,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) @@ -2007,17 +2394,17 @@ func TestAppLogs(t *testing.T) { Then(). Expect(HealthIs(health.HealthStatusHealthy)). And(func(app *Application) { - out, err := RunCli("app", "logs", app.Name, "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") + out, err := RunCliWithRetry(appLogsRetryCount, "app", "logs", app.Name, "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", app.Name, "--kind", "Pod") + out, err := RunCliWithRetry(appLogsRetryCount, "app", "logs", app.Name, "--kind", "Pod") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", app.Name, "--kind", "Service") + out, err := RunCliWithRetry(appLogsRetryCount, "app", "logs", app.Name, "--kind", "Service") assert.NoError(t, err) assert.NotContains(t, out, "Hi") }) diff --git a/test/e2e/app_multiple_sources_test.go b/test/e2e/app_multiple_sources_test.go index f7bf00c143d9b..69290edf2a856 100644 --- a/test/e2e/app_multiple_sources_test.go +++ b/test/e2e/app_multiple_sources_test.go @@ -3,11 +3,12 @@ package e2e import ( "testing" + "github.com/stretchr/testify/assert" + . "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" . "github.com/argoproj/argo-cd/v2/util/argo" - "github.com/stretchr/testify/assert" ) func TestMultiSourceAppCreation(t *testing.T) { @@ -24,7 +25,6 @@ func TestMultiSourceAppCreation(t *testing.T) { When(). CreateMultiSourceAppFromFile(). Then(). - Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). And(func(app *Application) { assert.Equal(t, Name(), app.Name) for i, source := range app.Spec.GetSources() { @@ -42,7 +42,8 @@ func TestMultiSourceAppCreation(t *testing.T) { assert.Contains(t, output, Name()) }). Expect(Success("")). - When().Refresh(RefreshTypeNormal).Then(). + Given().Timeout(60). + When().Wait().Then(). Expect(Success("")). And(func(app *Application) { statusByName := map[string]SyncStatusCode{} @@ -78,7 +79,6 @@ func TestMultiSourceAppWithHelmExternalValueFiles(t *testing.T) { When(). CreateMultiSourceAppFromFile(). Then(). - Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). And(func(app *Application) { assert.Equal(t, Name(), app.Name) for i, source := range app.Spec.GetSources() { @@ -96,7 +96,8 @@ func TestMultiSourceAppWithHelmExternalValueFiles(t *testing.T) { assert.Contains(t, output, Name()) }). Expect(Success("")). - When().Refresh(RefreshTypeNormal).Then(). + Given().Timeout(60). + When().Wait().Then(). Expect(Success("")). And(func(app *Application) { statusByName := map[string]SyncStatusCode{} @@ -126,7 +127,6 @@ func TestMultiSourceAppWithSourceOverride(t *testing.T) { When(). CreateMultiSourceAppFromFile(). Then(). - Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). And(func(app *Application) { assert.Equal(t, Name(), app.Name) for i, source := range app.Spec.GetSources() { @@ -144,7 +144,8 @@ func TestMultiSourceAppWithSourceOverride(t *testing.T) { assert.Contains(t, output, Name()) }). Expect(Success("")). - When().Refresh(RefreshTypeNormal).Then(). + Given().Timeout(60). + When().Wait().Then(). Expect(Success("")). And(func(app *Application) { statusByName := map[string]SyncStatusCode{} diff --git a/test/e2e/app_namespaces_test.go b/test/e2e/app_namespaces_test.go index d66cbaa1494ef..033c34e9a70d3 100644 --- a/test/e2e/app_namespaces_test.go +++ b/test/e2e/app_namespaces_test.go @@ -20,7 +20,7 @@ func TestAppCreationInOtherNamespace(t *testing.T) { ctx := Given(t) ctx. Path(guestbookPath). - SetAppNamespace(ArgoCDAppNamespace). + SetAppNamespace(AppNamespace()). When(). CreateApp(). Then(). @@ -83,7 +83,7 @@ func TestDeletingNamespacedAppStuckInSync(t *testing.T) { }) }). Async(true). - SetAppNamespace(ArgoCDAppNamespace). + SetAppNamespace(AppNamespace()). Path("hook-custom-health"). When(). CreateApp(). diff --git a/test/e2e/app_skipreconcile_test.go b/test/e2e/app_skipreconcile_test.go new file mode 100644 index 0000000000000..2ea28812756a8 --- /dev/null +++ b/test/e2e/app_skipreconcile_test.go @@ -0,0 +1,45 @@ +package e2e + +import ( + "testing" + + "github.com/argoproj/argo-cd/v2/common" + . "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + . "github.com/argoproj/argo-cd/v2/test/e2e/fixture/app" +) + +func TestAppSkipReconcileTrue(t *testing.T) { + Given(t). + Path(guestbookPath). + When(). + // app should have no status + CreateFromFile(func(app *Application) { + app.Annotations = map[string]string{common.AnnotationKeyAppSkipReconcile: "true"} + }). + Then(). + Expect(NoStatus()) +} + +func TestAppSkipReconcileFalse(t *testing.T) { + Given(t). + Path(guestbookPath). + When(). + // app should have status + CreateFromFile(func(app *Application) { + app.Annotations = map[string]string{common.AnnotationKeyAppSkipReconcile: "false"} + }). + Then(). + Expect(StatusExists()) +} + +func TestAppSkipReconcileNonBooleanValue(t *testing.T) { + Given(t). + Path(guestbookPath). + When(). + // app should have status + CreateFromFile(func(app *Application) { + app.Annotations = map[string]string{common.AnnotationKeyAppSkipReconcile: "not a boolean value"} + }). + Then(). + Expect(StatusExists()) +} 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 913eb73079de1..0d4d8ea3498f5 100644 --- a/test/e2e/applicationset_test.go +++ b/test/e2e/applicationset_test.go @@ -1,7 +1,9 @@ package e2e import ( + "fmt" "io" + "net" "net/http" "net/http/httptest" "strings" @@ -11,13 +13,19 @@ import ( corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/test/e2e/fixture" + + "github.com/stretchr/testify/assert" + . "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets" "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets/utils" . "github.com/argoproj/argo-cd/v2/util/errors" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application" ) var ( @@ -40,10 +48,890 @@ var ( Message: "ApplicationSet up to date", Reason: v1alpha1.ApplicationSetReasonApplicationSetUpToDate, }, - } -) + } +) + +func TestSimpleListGeneratorExternalNamespace(t *testing.T) { + + var externalNamespace = string(utils.ArgoCDExternalNamespace) + + 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", + }, + }, + } + var expectedAppNewNamespace *argov1alpha1.Application + var expectedAppNewMetadata *argov1alpha1.Application + + Given(t). + // Create a ListGenerator-based ApplicationSet + 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})). + + // 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.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)). + + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewMetadata})) + +} + +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{ + 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"}, + }, + 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().Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "simple-list-generator", + }, + Spec: v1alpha1.ApplicationSetSpec{ + 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})). + + // 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.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", ExpectedConditions)). + + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewMetadata})) + +} + +func TestSimpleListGeneratorGoTemplate(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"}, + }, + 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().Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "simple-list-generator", + }, + 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})). + + // 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.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", ExpectedConditions)). + + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewMetadata})) + +} + +func TestCreateApplicationDespiteParamsError(t *testing.T) { + expectedErrorMessage := `failed to execute go template {{.cluster}}-guestbook: template: :1:2: executing "" at <.cluster>: map has no entry for key "cluster"` + expectedConditionsParamsError := []v1alpha1.ApplicationSetCondition{ + { + Type: v1alpha1.ApplicationSetConditionErrorOccurred, + Status: v1alpha1.ApplicationSetConditionStatusTrue, + Message: expectedErrorMessage, + Reason: v1alpha1.ApplicationSetReasonRenderTemplateParamsError, + }, + { + Type: v1alpha1.ApplicationSetConditionParametersGenerated, + Status: v1alpha1.ApplicationSetConditionStatusFalse, + Message: expectedErrorMessage, + Reason: v1alpha1.ApplicationSetReasonErrorOccurred, + }, + { + Type: v1alpha1.ApplicationSetConditionResourcesUpToDate, + Status: v1alpha1.ApplicationSetConditionStatusFalse, + Message: expectedErrorMessage, + Reason: v1alpha1.ApplicationSetReasonRenderTemplateParamsError, + }, + } + 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"}, + }, + 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", + }, + }, + } + + Given(t). + // Create a ListGenerator-based ApplicationSet + When().Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "simple-list-generator", + }, + Spec: v1alpha1.ApplicationSetSpec{ + GoTemplate: true, + GoTemplateOptions: []string{"missingkey=error"}, + 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"}`), + }, + { + Raw: []byte(`{"invalidCluster": "invalid-cluster","url": "https://kubernetes.default.svc"}`), + }}, + }, + }, + }, + }, + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{expectedApp})). + + // verify the ApplicationSet status conditions were set correctly + Expect(ApplicationSetHasConditions("simple-list-generator", expectedConditionsParamsError)). + + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{expectedApp})) + +} + +func TestRenderHelmValuesObject(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"}, + }, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "helm-guestbook", + Helm: &argov1alpha1.ApplicationSourceHelm{ + ValuesObject: &runtime.RawExtension{ + // This will always be converted as yaml + Raw: []byte(`{"some":{"string":"Hello world"}}`), + }, + }, + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook", + }, + }, + } + + Given(t). + // Create a ListGenerator-based ApplicationSet + When().Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "test-values-object", + }, + 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: "helm-guestbook", + Helm: &argov1alpha1.ApplicationSourceHelm{ + ValuesObject: &runtime.RawExtension{ + Raw: []byte(`{"some":{"string":"{{.test}}"}}`), + }, + }, + }, + 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", "test": "Hello world"}`), + }}, + }, + }, + }, + }, + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{expectedApp})). + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{expectedApp})) + +} + +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{ + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster-guestbook-sync-policy-create-update", + Namespace: utils.ArgoCDNamespace, + 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().Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "sync-policy-create-update", + }, + Spec: v1alpha1.ApplicationSetSpec{ + GoTemplate: true, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{.cluster}}-guestbook-sync-policy-create-update"}, + 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})). -func TestSimpleListGenerator(t *testing.T) { + // 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 + // Update as well the policy + // As policy is create-update, updates must reflected + 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", + } + applicationsSyncPolicy := argov1alpha1.ApplicationsSyncPolicyCreateUpdate + appset.Spec.SyncPolicy = &argov1alpha1.ApplicationSetSyncPolicy{ + ApplicationsSync: &applicationsSyncPolicy, + } + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{*expectedAppNewMetadata})). + + // Update the list and remove element + // As policy is create-update, app deletion must not be reflected + When(). + Update(func(appset *v1alpha1.ApplicationSet) { + appset.Spec.Generators = []v1alpha1.ApplicationSetGenerator{} + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{*expectedAppNewMetadata})). + + // verify the ApplicationSet status conditions were set correctly + Expect(ApplicationSetHasConditions("sync-policy-create-update", ExpectedConditions)). + + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewMetadata})) + +} + +func TestSyncPolicyCreateDelete(t *testing.T) { expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ @@ -51,7 +939,7 @@ func TestSimpleListGenerator(t *testing.T) { APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ - Name: "my-cluster-guestbook", + Name: "my-cluster-guestbook-sync-policy-create-delete", Namespace: utils.ArgoCDNamespace, Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, @@ -69,16 +957,16 @@ func TestSimpleListGenerator(t *testing.T) { }, } var expectedAppNewNamespace *argov1alpha1.Application - var expectedAppNewMetadata *argov1alpha1.Application Given(t). // Create a ListGenerator-based ApplicationSet When().Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ - Name: "simple-list-generator", + Name: "sync-policy-create-delete", }, Spec: v1alpha1.ApplicationSetSpec{ + GoTemplate: true, Template: v1alpha1.ApplicationSetTemplate{ - ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{cluster}}-guestbook"}, + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{.cluster}}-guestbook-sync-policy-create-delete"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", Source: &argov1alpha1.ApplicationSource{ @@ -87,7 +975,7 @@ func TestSimpleListGenerator(t *testing.T) { Path: "guestbook", }, Destination: argov1alpha1.ApplicationDestination{ - Server: "{{url}}", + Server: "{{.url}}", Namespace: "guestbook", }, }, @@ -114,28 +1002,36 @@ func TestSimpleListGenerator(t *testing.T) { 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 + // Update the metadata fields in the appset template + // Update as well the policy + // As policy is create-delete, updates must not be reflected 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})). + applicationsSyncPolicy := argov1alpha1.ApplicationsSyncPolicyCreateDelete + appset.Spec.SyncPolicy = &argov1alpha1.ApplicationSetSyncPolicy{ + ApplicationsSync: &applicationsSyncPolicy, + } + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{*expectedAppNewNamespace})). + + // Update the list and remove element + // As policy is create-delete, app deletion must be reflected + When(). + Update(func(appset *v1alpha1.ApplicationSet) { + appset.Spec.Generators = []v1alpha1.ApplicationSetGenerator{} + }).Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewNamespace})). // verify the ApplicationSet status conditions were set correctly - Expect(ApplicationSetHasConditions("simple-list-generator", ExpectedConditions)). + Expect(ApplicationSetHasConditions("sync-policy-create-delete", ExpectedConditions)). - // Delete the ApplicationSet, and verify it deletes the Applications + // Delete the ApplicationSet When(). - Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewMetadata})) + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewNamespace})) } -func TestSimpleListGeneratorGoTemplate(t *testing.T) { +func TestSyncPolicyCreateOnly(t *testing.T) { expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ @@ -143,7 +1039,7 @@ func TestSimpleListGeneratorGoTemplate(t *testing.T) { APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ - Name: "my-cluster-guestbook", + Name: "my-cluster-guestbook-sync-policy-create-only", Namespace: utils.ArgoCDNamespace, Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, @@ -161,17 +1057,16 @@ func TestSimpleListGeneratorGoTemplate(t *testing.T) { }, } var expectedAppNewNamespace *argov1alpha1.Application - var expectedAppNewMetadata *argov1alpha1.Application Given(t). // Create a ListGenerator-based ApplicationSet When().Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ - Name: "simple-list-generator", + Name: "sync-policy-create-only", }, Spec: v1alpha1.ApplicationSetSpec{ GoTemplate: true, Template: v1alpha1.ApplicationSetTemplate{ - ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{.cluster}}-guestbook"}, + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{.cluster}}-guestbook-sync-policy-create-only"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", Source: &argov1alpha1.ApplicationSource{ @@ -207,24 +1102,32 @@ func TestSimpleListGeneratorGoTemplate(t *testing.T) { 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 + // Update the metadata fields in the appset template + // Update as well the policy + // As policy is create-only, updates must not be reflected 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})). + applicationsSyncPolicy := argov1alpha1.ApplicationsSyncPolicyCreateOnly + appset.Spec.SyncPolicy = &argov1alpha1.ApplicationSetSyncPolicy{ + ApplicationsSync: &applicationsSyncPolicy, + } + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{*expectedAppNewNamespace})). + + // Update the list and remove element + // As policy is create-only, app deletion must not be reflected + When(). + Update(func(appset *v1alpha1.ApplicationSet) { + appset.Spec.Generators = []v1alpha1.ApplicationSetGenerator{} + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{*expectedAppNewNamespace})). // verify the ApplicationSet status conditions were set correctly - Expect(ApplicationSetHasConditions("simple-list-generator", ExpectedConditions)). + Expect(ApplicationSetHasConditions("sync-policy-create-only", ExpectedConditions)). // Delete the ApplicationSet, and verify it deletes the Applications When(). - Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewMetadata})) + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewNamespace})) } @@ -232,12 +1135,12 @@ func TestSimpleGitDirectoryGenerator(t *testing.T) { generateExpectedApp := func(name string) argov1alpha1.Application { return argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -341,12 +1244,12 @@ func TestSimpleGitDirectoryGeneratorGoTemplate(t *testing.T) { generateExpectedApp := func(name string) argov1alpha1.Application { return argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -452,12 +1355,12 @@ func TestSimpleGitFilesGenerator(t *testing.T) { generateExpectedApp := func(name string) argov1alpha1.Application { return argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -561,12 +1464,12 @@ func TestSimpleGitFilesGeneratorGoTemplate(t *testing.T) { generateExpectedApp := func(name string) argov1alpha1.Application { return argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -670,7 +1573,7 @@ func TestSimpleGitFilesPreserveResourcesOnDeletion(t *testing.T) { Given(t). When(). - CreateNamespace(). + CreateNamespace(utils.ApplicationsResourcesNamespace). // Create a GitGenerator-based ApplicationSet Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ Name: "simple-git-generator", @@ -687,7 +1590,7 @@ func TestSimpleGitFilesPreserveResourcesOnDeletion(t *testing.T) { }, Destination: argov1alpha1.ApplicationDestination{ Server: "https://kubernetes.default.svc", - Namespace: utils.ApplicationSetNamespace, + Namespace: utils.ApplicationsResourcesNamespace, }, // Automatically create resources @@ -730,7 +1633,7 @@ func TestSimpleGitFilesPreserveResourcesOnDeletionGoTemplate(t *testing.T) { Given(t). When(). - CreateNamespace(). + CreateNamespace(utils.ApplicationsResourcesNamespace). // Create a GitGenerator-based ApplicationSet Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ Name: "simple-git-generator", @@ -748,7 +1651,7 @@ func TestSimpleGitFilesPreserveResourcesOnDeletionGoTemplate(t *testing.T) { }, Destination: argov1alpha1.ApplicationDestination{ Server: "https://kubernetes.default.svc", - Namespace: utils.ApplicationSetNamespace, + Namespace: utils.ApplicationsResourcesNamespace, }, // Automatically create resources @@ -971,25 +1874,42 @@ func githubSCMMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) t.Fail() } default: - w.WriteHeader(404) + w.WriteHeader(http.StatusNotFound) } } } -func TestSimpleSCMProviderGenerator(t *testing.T) { +func testServerWithPort(t *testing.T, port int, handler http.Handler) *httptest.Server { // Use mocked API response to avoid rate-limiting. - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) + if err != nil { + t.Error(fmt.Errorf("Unable to start server %w", err)) + } + + ts := httptest.NewUnstartedServer(handler) + + ts.Listener.Close() + ts.Listener = l + + return ts +} + +func TestSimpleSCMProviderGenerator(t *testing.T) { + + ts := testServerWithPort(t, 8341, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { githubSCMMockHandler(t)(w, r) })) + ts.Start() + defer ts.Close() expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: "argo-cd-guestbook", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -1050,19 +1970,20 @@ func TestSimpleSCMProviderGenerator(t *testing.T) { } func TestSimpleSCMProviderGeneratorGoTemplate(t *testing.T) { - // Use mocked API response to avoid rate-limiting. - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ts := testServerWithPort(t, 8342, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { githubSCMMockHandler(t)(w, r) })) + ts.Start() + defer ts.Close() expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: "argo-cd-guestbook", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -1123,15 +2044,90 @@ func TestSimpleSCMProviderGeneratorGoTemplate(t *testing.T) { }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{expectedApp})) } +func TestSCMProviderGeneratorSCMProviderNotAllowed(t *testing.T) { + expectedApp := argov1alpha1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "argo-cd-guestbook", + Namespace: fixture.TestNamespace(), + Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, + }, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "git@github.com:argoproj/argo-cd.git", + TargetRevision: "master", + Path: "guestbook", + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook", + }, + }, + } + + // Because you can't &"". + repoMatch := "argo-cd" + + Given(t). + // Create an SCMProviderGenerator-based ApplicationSet + When().Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "scm-provider-generator-scm-provider-not-allowed", + }, + Spec: v1alpha1.ApplicationSetSpec{ + GoTemplate: true, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{ .repository }}-guestbook"}, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "{{ .url }}", + TargetRevision: "{{ .branch }}", + Path: "guestbook", + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook", + }, + }, + }, + Generators: []v1alpha1.ApplicationSetGenerator{ + { + SCMProvider: &v1alpha1.SCMProviderGenerator{ + Github: &v1alpha1.SCMProviderGeneratorGithub{ + Organization: "argoproj", + API: "http://myservice.mynamespace.svc.cluster.local", + }, + Filters: []v1alpha1.SCMProviderGeneratorFilter{ + { + RepositoryMatch: &repoMatch, + }, + }, + }, + }, + }, + }, + }).Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{expectedApp})). + And(func() { + // app should be listed + output, err := fixture.RunCli("appset", "get", "scm-provider-generator-scm-provider-not-allowed") + assert.NoError(t, err) + assert.Contains(t, output, "scm provider not allowed") + }) +} + func TestCustomApplicationFinalizers(t *testing.T) { expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: "my-cluster-guestbook", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -1192,12 +2188,12 @@ func TestCustomApplicationFinalizers(t *testing.T) { func TestCustomApplicationFinalizersGoTemplate(t *testing.T) { expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: "my-cluster-guestbook", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -1269,6 +2265,10 @@ func githubPullMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request "name": "preview" } ], + "base": { + "ref": "master", + "sha": "7a4a5c987fdfb2b0629e9dbf5f31636c69ba4775" + }, "head": { "ref": "pull-request", "sha": "824a5c987fdfb2b0629e9dbf5f31636c69ba4772" @@ -1279,25 +2279,28 @@ func githubPullMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request t.Fail() } default: - w.WriteHeader(404) + w.WriteHeader(http.StatusNotFound) } } } func TestSimplePullRequestGenerator(t *testing.T) { - // Use mocked API response to avoid rate-limiting. - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + ts := testServerWithPort(t, 8343, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { githubPullMockHandler(t)(w, r) })) + ts.Start() + defer ts.Close() + expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: "guestbook-1", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -1360,19 +2363,21 @@ func TestSimplePullRequestGenerator(t *testing.T) { } func TestSimplePullRequestGeneratorGoTemplate(t *testing.T) { - // Use mocked API response to avoid rate-limiting. - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ts := testServerWithPort(t, 8344, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { githubPullMockHandler(t)(w, r) })) + ts.Start() + defer ts.Close() + expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: "guestbook-1", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, Labels: map[string]string{"app": "preview"}, }, @@ -1438,17 +2443,100 @@ func TestSimplePullRequestGeneratorGoTemplate(t *testing.T) { }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{expectedApp})) } +func TestPullRequestGeneratorNotAllowedSCMProvider(t *testing.T) { + + expectedApp := argov1alpha1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "guestbook-1", + Namespace: fixture.TestNamespace(), + Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, + Labels: map[string]string{ + "app": "preview", + }, + }, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "git@github.com:applicationset-test-org/argocd-example-apps.git", + TargetRevision: "824a5c987fdfb2b0629e9dbf5f31636c69ba4772", + Path: "kustomize-guestbook", + Kustomize: &argov1alpha1.ApplicationSourceKustomize{ + NamePrefix: "guestbook-1", + }, + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook-pull-request", + }, + }, + } + + Given(t). + // Create an PullRequestGenerator-based ApplicationSet + When().Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "pull-request-generator-not-allowed-scm", + }, + Spec: v1alpha1.ApplicationSetSpec{ + GoTemplate: true, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ + Name: "guestbook-{{ .number }}", + Labels: map[string]string{"app": "{{index .labels 0}}"}}, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "git@github.com:applicationset-test-org/argocd-example-apps.git", + TargetRevision: "{{ .head_sha }}", + Path: "kustomize-guestbook", + Kustomize: &argov1alpha1.ApplicationSourceKustomize{ + NamePrefix: "guestbook-{{ .number }}", + }, + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook-{{ .branch }}", + }, + }, + }, + Generators: []v1alpha1.ApplicationSetGenerator{ + { + PullRequest: &v1alpha1.PullRequestGenerator{ + Github: &v1alpha1.PullRequestGeneratorGithub{ + API: "http://myservice.mynamespace.svc.cluster.local", + Owner: "applicationset-test-org", + Repo: "argocd-example-apps", + Labels: []string{ + "preview", + }, + }, + }, + }, + }, + }, + }).Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{expectedApp})). + And(func() { + // app should be listed + output, err := fixture.RunCli("appset", "get", "pull-request-generator-not-allowed-scm") + assert.NoError(t, err) + assert.Contains(t, output, "scm provider not allowed") + }) +} + func TestGitGeneratorPrivateRepo(t *testing.T) { FailOnErr(fixture.RunCli("repo", "add", fixture.RepoURL(fixture.RepoURLTypeHTTPS), "--username", fixture.GitUsername, "--password", fixture.GitPassword, "--insecure-skip-server-verification")) generateExpectedApp := func(name string) argov1alpha1.Application { return argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -1518,12 +2606,12 @@ func TestGitGeneratorPrivateRepoGoTemplate(t *testing.T) { generateExpectedApp := func(name string) argov1alpha1.Application { return argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: name, - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ diff --git a/test/e2e/cli_test.go b/test/e2e/cli_test.go index 028d3d516764e..8e87ea16f4469 100644 --- a/test/e2e/cli_test.go +++ b/test/e2e/cli_test.go @@ -31,7 +31,7 @@ func TestCliAppCommand(t *testing.T) { output, err := RunCli("app", "list") assert.NoError(t, err) expected := Tmpl( - `{{.Name}} https://kubernetes.default.svc {{.Namespace}} default Synced Healthy `, + `{{.Name}} https://kubernetes.default.svc {{.Namespace}} default Synced Healthy Manual `, map[string]interface{}{"Name": Name(), "Namespace": DeploymentNamespace()}) assert.Contains(t, NormalizeOutput(output), expected) }) diff --git a/test/e2e/cluster_generator_test.go b/test/e2e/cluster_generator_test.go index c09fc9ed2fa34..1d5699e23503d 100644 --- a/test/e2e/cluster_generator_test.go +++ b/test/e2e/cluster_generator_test.go @@ -4,15 +4,21 @@ import ( "testing" "time" + "github.com/argoproj/argo-cd/v2/test/e2e/fixture" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" . "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets" "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets/utils" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application" ) -func TestSimpleClusterGenerator(t *testing.T) { +func TestSimpleClusterGeneratorExternalNamespace(t *testing.T) { + + var externalNamespace = string(utils.ArgoCDExternalNamespace) expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ @@ -21,7 +27,107 @@ func TestSimpleClusterGenerator(t *testing.T) { }, ObjectMeta: metav1.ObjectMeta{ Name: "cluster1-guestbook", - Namespace: utils.ArgoCDNamespace, + 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{ + Name: "cluster1", + Namespace: "guestbook", + }, + }, + } + + var expectedAppNewNamespace *argov1alpha1.Application + var expectedAppNewMetadata *argov1alpha1.Application + + Given(t). + // Create a ClusterGenerator-based ApplicationSet + When(). + CreateClusterSecret("my-secret", "cluster1", "https://kubernetes.default.svc"). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace). + CreateNamespace(externalNamespace). + Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "simple-cluster-generator", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{name}}-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{ + Name: "{{name}}", + // Server: "{{server}}", + Namespace: "guestbook", + }, + }, + }, + Generators: []v1alpha1.ApplicationSetGenerator{ + { + Clusters: &v1alpha1.ClusterGenerator{ + Selector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "argocd.argoproj.io/secret-type": "cluster", + }, + }, + }, + }, + }, + }, + }).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.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})). + + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewNamespace})) +} + +func TestSimpleClusterGenerator(t *testing.T) { + + expectedApp := argov1alpha1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1-guestbook", + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -109,12 +215,12 @@ func TestSimpleClusterGenerator(t *testing.T) { func TestClusterGeneratorWithLocalCluster(t *testing.T) { expectedAppTemplate := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: "in-cluster-guestbook", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -226,12 +332,12 @@ func TestSimpleClusterGeneratorAddingCluster(t *testing.T) { expectedAppTemplate := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: "{{name}}-guestbook", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -308,12 +414,12 @@ func TestSimpleClusterGeneratorDeletingCluster(t *testing.T) { expectedAppTemplate := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: "{{name}}-guestbook", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ diff --git a/test/e2e/cluster_objects_test.go b/test/e2e/cluster_objects_test.go index 4388932296673..4299a35c55c00 100644 --- a/test/e2e/cluster_objects_test.go +++ b/test/e2e/cluster_objects_test.go @@ -5,12 +5,14 @@ import ( "github.com/argoproj/gitops-engine/pkg/health" . "github.com/argoproj/gitops-engine/pkg/sync/common" + "github.com/stretchr/testify/assert" . "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" + "github.com/argoproj/argo-cd/v2/util/argo" ) -// ensure that cluster scoped objects, like a cluster role, as a hok, can be successfully deployed func TestClusterRoleBinding(t *testing.T) { Given(t). Path("cluster-role"). @@ -20,5 +22,35 @@ func TestClusterRoleBinding(t *testing.T) { Then(). Expect(OperationPhaseIs(OperationSucceeded)). Expect(HealthIs(health.HealthStatusHealthy)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + And(func(app *Application) { + diffOutput, err := RunCli("app", "diff", app.Name, "--revision=HEAD") + assert.NoError(t, err) + assert.Empty(t, diffOutput) + }). + When(). + SetTrackingMethod(string(argo.TrackingMethodAnnotation)). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(HealthIs(health.HealthStatusHealthy)). + And(func(app *Application) { + diffOutput, err := RunCli("app", "diff", app.Name, "--revision=HEAD") + assert.NoError(t, err) + assert.Empty(t, diffOutput) + }) +} + +// ensure that cluster scoped objects, like a cluster role, as a hook, can be successfully deployed +func TestClusterRoleBindingHook(t *testing.T) { + Given(t). + Path("cluster-role-hook"). + When(). + CreateApp(). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(HealthIs(health.HealthStatusHealthy)). Expect(SyncStatusIs(SyncStatusCodeSynced)) } diff --git a/test/e2e/cluster_test.go b/test/e2e/cluster_test.go index 671acb735e193..2074a6aa1b7b1 100644 --- a/test/e2e/cluster_test.go +++ b/test/e2e/cluster_test.go @@ -5,6 +5,7 @@ import ( "net/url" "strings" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -13,6 +14,7 @@ import ( "github.com/argoproj/argo-cd/v2/test/e2e/fixture" . "github.com/argoproj/argo-cd/v2/test/e2e/fixture" accountFixture "github.com/argoproj/argo-cd/v2/test/e2e/fixture/account" + "github.com/argoproj/argo-cd/v2/test/e2e/fixture/app" clusterFixture "github.com/argoproj/argo-cd/v2/test/e2e/fixture/cluster" . "github.com/argoproj/argo-cd/v2/util/errors" ) @@ -21,16 +23,38 @@ func TestClusterList(t *testing.T) { SkipIfAlreadyRun(t) defer RecordTestRun(t) + last := "" + expected := fmt.Sprintf(`SERVER NAME VERSION STATUS MESSAGE PROJECT +https://kubernetes.default.svc in-cluster %v Successful `, GetVersions().ServerVersion) + clusterFixture. Given(t). - Project(ProjectName). + Project(ProjectName) + + // We need an application targeting the cluster, otherwise the test will + // fail if run isolated. + app.GivenWithSameState(t). + Path(guestbookPath). When(). - List(). - Then(). - AndCLIOutput(func(output string, err error) { - assert.Equal(t, fmt.Sprintf(`SERVER NAME VERSION STATUS MESSAGE PROJECT -https://kubernetes.default.svc in-cluster %v Successful `, GetVersions().ServerVersion), output) - }) + CreateApp() + + tries := 5 + for i := 0; i <= tries; i += 1 { + clusterFixture.GivenWithSameState(t). + When(). + List(). + Then(). + AndCLIOutput(func(output string, err error) { + last = output + }) + if expected == last { + break + } else if i < tries { + // We retry with a simple backoff + time.Sleep(time.Duration(i+1) * time.Second) + } + } + assert.Equal(t, expected, last) } func TestClusterAdd(t *testing.T) { diff --git a/test/e2e/clusterdecisiongenerator_e2e_test.go b/test/e2e/clusterdecisiongenerator_e2e_test.go index 44993dd409fde..5f0d6ff6ae3c7 100644 --- a/test/e2e/clusterdecisiongenerator_e2e_test.go +++ b/test/e2e/clusterdecisiongenerator_e2e_test.go @@ -3,17 +3,23 @@ package e2e import ( "testing" + "github.com/argoproj/argo-cd/v2/test/e2e/fixture" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" . "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets" "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets/utils" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application" ) var tenSec = int64(10) -func TestSimpleClusterDecisionResourceGenerator(t *testing.T) { +func TestSimpleClusterDecisionResourceGeneratorExternalNamespace(t *testing.T) { + + var externalNamespace = string(utils.ArgoCDExternalNamespace) expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ @@ -22,7 +28,115 @@ func TestSimpleClusterDecisionResourceGenerator(t *testing.T) { }, ObjectMeta: metav1.ObjectMeta{ Name: "cluster1-guestbook", - Namespace: utils.ArgoCDNamespace, + 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{ + Name: "cluster1", + Namespace: "guestbook", + }, + }, + } + + var expectedAppNewNamespace *argov1alpha1.Application + var expectedAppNewMetadata *argov1alpha1.Application + + clusterList := []interface{}{ + map[string]interface{}{ + "clusterName": "cluster1", + "reason": "argotest", + }, + } + + Given(t). + // Create a ClusterGenerator-based ApplicationSet + When(). + CreateClusterSecret("my-secret", "cluster1", "https://kubernetes.default.svc"). + CreatePlacementRoleAndRoleBinding(). + CreatePlacementDecisionConfigMap("my-configmap"). + CreatePlacementDecision("my-placementdecision"). + StatusUpdatePlacementDecision("my-placementdecision", clusterList). + CreateNamespace(externalNamespace). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace). + Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "simple-cluster-generator", + }, + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{name}}-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{ + Name: "{{clusterName}}", + // Server: "{{server}}", + Namespace: "guestbook", + }, + }, + }, + Generators: []v1alpha1.ApplicationSetGenerator{ + { + ClusterDecisionResource: &v1alpha1.DuckTypeGenerator{ + ConfigMapRef: "my-configmap", + Name: "my-placementdecision", + }, + }, + }, + }, + }).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.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})). + + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewNamespace})) +} + +func TestSimpleClusterDecisionResourceGenerator(t *testing.T) { + + expectedApp := argov1alpha1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster1-guestbook", + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -119,12 +233,12 @@ func TestSimpleClusterDecisionResourceGeneratorAddingCluster(t *testing.T) { expectedAppTemplate := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: "{{name}}-guestbook", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -214,12 +328,12 @@ func TestSimpleClusterDecisionResourceGeneratorDeletingClusterSecret(t *testing. expectedAppTemplate := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: "{{name}}-guestbook", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -311,12 +425,12 @@ func TestSimpleClusterDecisionResourceGeneratorDeletingClusterFromResource(t *te expectedAppTemplate := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: "{{name}}-guestbook", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ diff --git a/test/e2e/custom_tool_test.go b/test/e2e/custom_tool_test.go index cd587f42693b6..7370fb5478ad3 100644 --- a/test/e2e/custom_tool_test.go +++ b/test/e2e/custom_tool_test.go @@ -2,6 +2,7 @@ package e2e import ( "os" + "path/filepath" "sort" "strings" "testing" @@ -10,6 +11,7 @@ import ( "github.com/argoproj/gitops-engine/pkg/health" . "github.com/argoproj/gitops-engine/pkg/sync/common" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" . "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" . "github.com/argoproj/argo-cd/v2/test/e2e/fixture" @@ -21,56 +23,41 @@ import ( func TestCustomToolWithGitCreds(t *testing.T) { ctx := Given(t) ctx. - // path does not matter, we ignore it - ConfigManagementPlugin( - ConfigManagementPlugin{ - Name: Name(), - Generate: Command{ - Command: []string{"sh", "-c"}, - Args: []string{`echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"GitAskpass\": \"$GIT_ASKPASS\"}}}"`}, - }, - }, - ). + And(func() { + go startCMPServer(t, "./testdata/cmp-gitcreds") + time.Sleep(1 * time.Second) + t.Setenv("ARGOCD_BINARY_NAME", "argocd") + }). CustomCACertAdded(). // add the private repo with credentials HTTPSRepoURLAdded(true). RepoURLType(RepoURLTypeHTTPS). - Path("https-kustomize-base"). + Path("cmp-gitcreds"). When(). CreateApp(). Sync(). Then(). Expect(OperationPhaseIs(OperationSucceeded)). Expect(SyncStatusIs(SyncStatusCodeSynced)). - Expect(HealthIs(health.HealthStatusHealthy)). - And(func(app *Application) { - output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.GitAskpass}") - assert.NoError(t, err) - assert.Equal(t, "argocd", output) - }) + Expect(HealthIs(health.HealthStatusHealthy)) } // make sure we can echo back the Git creds func TestCustomToolWithGitCredsTemplate(t *testing.T) { ctx := Given(t) ctx. - // path does not matter, we ignore it - ConfigManagementPlugin( - ConfigManagementPlugin{ - Name: Name(), - Generate: Command{ - Command: []string{"sh", "-c"}, - Args: []string{`echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"GitAskpass\": \"$GIT_ASKPASS\", \"GitUsername\": \"$GIT_USERNAME\", \"GitPassword\": \"$GIT_PASSWORD\"}}}"`}, - }, - }, - ). + And(func() { + go startCMPServer(t, "./testdata/cmp-gitcredstemplate") + time.Sleep(1 * time.Second) + t.Setenv("ARGOCD_BINARY_NAME", "argocd") + }). CustomCACertAdded(). // add the git creds template HTTPSCredentialsUserPassAdded(). // add the private repo without credentials HTTPSRepoURLAdded(false). RepoURLType(RepoURLTypeHTTPS). - Path("https-kustomize-base"). + Path("cmp-gitcredstemplate"). When(). CreateApp(). Sync(). @@ -78,11 +65,6 @@ func TestCustomToolWithGitCredsTemplate(t *testing.T) { Expect(OperationPhaseIs(OperationSucceeded)). Expect(SyncStatusIs(SyncStatusCodeSynced)). Expect(HealthIs(health.HealthStatusHealthy)). - And(func(app *Application) { - output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.GitAskpass}") - assert.NoError(t, err) - assert.Equal(t, "argocd", output) - }). And(func(app *Application) { output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.GitUsername}") assert.NoError(t, err) @@ -99,24 +81,21 @@ func TestCustomToolWithGitCredsTemplate(t *testing.T) { func TestCustomToolWithEnv(t *testing.T) { ctx := Given(t) ctx. - // path does not matter, we ignore it - ConfigManagementPlugin( - ConfigManagementPlugin{ - Name: Name(), - Generate: Command{ - Command: []string{"sh", "-c"}, - Args: []string{`echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"Foo\": \"$ARGOCD_ENV_FOO\", \"KubeVersion\": \"$KUBE_VERSION\", \"KubeApiVersion\": \"$KUBE_API_VERSIONS\",\"Bar\": \"baz\"}}}"`}, - }, - }, - ). + And(func() { + go startCMPServer(t, "./testdata/cmp-fileName") + time.Sleep(1 * time.Second) + t.Setenv("ARGOCD_BINARY_NAME", "argocd") + }). // does not matter what the path is - Path("guestbook"). + Path("cmp-fileName"). When(). CreateFromFile(func(app *Application) { - app.Spec.GetSource().Plugin.Env = Env{{ - Name: "FOO", - Value: "bar", - }} + app.Spec.Source.Plugin = &ApplicationSourcePlugin{ + Env: Env{{ + Name: "FOO", + Value: "bar", + }}, + } }). Sync(). Then(). @@ -156,25 +135,23 @@ func TestCustomToolWithEnv(t *testing.T) { }) } -//make sure we can sync and diff with --local +// make sure we can sync and diff with --local func TestCustomToolSyncAndDiffLocal(t *testing.T) { + testdataPath, err := filepath.Abs("testdata") + require.NoError(t, err) ctx := Given(t) + appPath := filepath.Join(testdataPath, "guestbook") ctx. - // path does not matter, we ignore it - ConfigManagementPlugin( - ConfigManagementPlugin{ - Name: Name(), - Generate: Command{ - Command: []string{"sh", "-c"}, - Args: []string{`echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"Foo\": \"$ARGOCD_ENV_FOO\", \"KubeVersion\": \"$KUBE_VERSION\", \"KubeApiVersion\": \"$KUBE_API_VERSIONS\",\"Bar\": \"baz\"}}}"`}, - }, - }, - ). + And(func() { + go startCMPServer(t, "./testdata/cmp-kustomize") + time.Sleep(1 * time.Second) + t.Setenv("ARGOCD_BINARY_NAME", "argocd") + }). // does not matter what the path is Path("guestbook"). When(). - CreateApp("--config-management-plugin", ctx.AppName()). - Sync("--local", "testdata/guestbook"). + CreateApp("--config-management-plugin", "cmp-kustomize-v1.0"). + Sync("--local", appPath, "--local-repo-root", testdataPath). Then(). Expect(OperationPhaseIs(OperationSucceeded)). Expect(SyncStatusIs(SyncStatusCodeSynced)). @@ -183,36 +160,36 @@ func TestCustomToolSyncAndDiffLocal(t *testing.T) { time.Sleep(1 * time.Second) }). And(func(app *Application) { - FailOnErr(RunCli("app", "sync", ctx.AppName(), "--local", "testdata/guestbook")) + FailOnErr(RunCli("app", "sync", ctx.AppName(), "--local", appPath, "--local-repo-root", testdataPath)) }). And(func(app *Application) { - FailOnErr(RunCli("app", "diff", ctx.AppName(), "--local", "testdata/guestbook")) + FailOnErr(RunCli("app", "diff", ctx.AppName(), "--local", appPath, "--local-repo-root", testdataPath)) }) } -func startCMPServer(configFile string) { +func startCMPServer(t *testing.T, configFile string) { pluginSockFilePath := TmpDir + PluginSockFilePath - os.Setenv("ARGOCD_BINARY_NAME", "argocd-cmp-server") + t.Setenv("ARGOCD_BINARY_NAME", "argocd-cmp-server") // ARGOCD_PLUGINSOCKFILEPATH should be set as the same value as repo server env var - os.Setenv("ARGOCD_PLUGINSOCKFILEPATH", pluginSockFilePath) + t.Setenv("ARGOCD_PLUGINSOCKFILEPATH", pluginSockFilePath) if _, err := os.Stat(pluginSockFilePath); os.IsNotExist(err) { // path/to/whatever does not exist err := os.Mkdir(pluginSockFilePath, 0700) - CheckError(err) + require.NoError(t, err) } FailOnErr(RunWithStdin("", "", "../../dist/argocd", "--config-dir-path", configFile)) } -//Discover by fileName +// Discover by fileName func TestCMPDiscoverWithFileName(t *testing.T) { pluginName := "cmp-fileName" Given(t). And(func() { - go startCMPServer("./testdata/cmp-fileName") + go startCMPServer(t, "./testdata/cmp-fileName") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). - Path(pluginName). + Path(pluginName + "/subdir"). When(). CreateApp(). Sync(). @@ -222,13 +199,13 @@ func TestCMPDiscoverWithFileName(t *testing.T) { Expect(HealthIs(health.HealthStatusHealthy)) } -//Discover by Find glob +// Discover by Find glob func TestCMPDiscoverWithFindGlob(t *testing.T) { Given(t). And(func() { - go startCMPServer("./testdata/cmp-find-glob") + go startCMPServer(t, "./testdata/cmp-find-glob") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path("guestbook"). When(). @@ -240,13 +217,13 @@ func TestCMPDiscoverWithFindGlob(t *testing.T) { Expect(HealthIs(health.HealthStatusHealthy)) } -//Discover by Plugin Name +// Discover by Plugin Name func TestCMPDiscoverWithPluginName(t *testing.T) { Given(t). And(func() { - go startCMPServer("./testdata/cmp-find-glob") + go startCMPServer(t, "./testdata/cmp-find-glob") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path("guestbook"). When(). @@ -261,15 +238,15 @@ func TestCMPDiscoverWithPluginName(t *testing.T) { Expect(HealthIs(health.HealthStatusHealthy)) } -//Discover by Find command +// Discover by Find command func TestCMPDiscoverWithFindCommandWithEnv(t *testing.T) { pluginName := "cmp-find-command" ctx := Given(t) ctx. And(func() { - go startCMPServer("./testdata/cmp-find-command") + go startCMPServer(t, "./testdata/cmp-find-command") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path(pluginName). When(). @@ -310,9 +287,9 @@ func TestCMPDiscoverWithFindCommandWithEnv(t *testing.T) { func TestPruneResourceFromCMP(t *testing.T) { Given(t). And(func() { - go startCMPServer("./testdata/cmp-find-glob") + go startCMPServer(t, "./testdata/cmp-find-glob") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path("guestbook"). When(). @@ -329,3 +306,74 @@ func TestPruneResourceFromCMP(t *testing.T) { assert.Error(t, err) }) } + +func TestPreserveFileModeForCMP(t *testing.T) { + Given(t). + And(func() { + go startCMPServer(t, "./testdata/cmp-preserve-file-mode") + time.Sleep(1 * time.Second) + t.Setenv("ARGOCD_BINARY_NAME", "argocd") + }). + Path("cmp-preserve-file-mode"). + When(). + CreateFromFile(func(app *Application) { + app.Spec.Source.Plugin = &ApplicationSourcePlugin{Name: "cmp-preserve-file-mode-v1.0"} + }). + Refresh(RefreshTypeNormal). + Then(). + And(func(app *Application) { + require.Len(t, app.Status.Resources, 1) + assert.Equal(t, "ConfigMap", app.Status.Resources[0].Kind) + }) +} + +func TestCMPWithSymlinkPartialFiles(t *testing.T) { + Given(t, WithTestData("testdata2")). + And(func() { + go startCMPServer(t, "./testdata2/cmp-symlink") + time.Sleep(1 * time.Second) + t.Setenv("ARGOCD_BINARY_NAME", "argocd") + }). + Path("guestbook-partial-symlink-files"). + When(). + CreateApp(). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(HealthIs(health.HealthStatusHealthy)) +} + +func TestCMPWithSymlinkFiles(t *testing.T) { + Given(t, WithTestData("testdata2")). + And(func() { + go startCMPServer(t, "./testdata2/cmp-symlink") + time.Sleep(1 * time.Second) + t.Setenv("ARGOCD_BINARY_NAME", "argocd") + }). + Path("guestbook-symlink-files"). + When(). + CreateApp(). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(HealthIs(health.HealthStatusHealthy)) +} + +func TestCMPWithSymlinkFolder(t *testing.T) { + Given(t, WithTestData("testdata2")). + And(func() { + go startCMPServer(t, "./testdata2/cmp-symlink") + time.Sleep(1 * time.Second) + t.Setenv("ARGOCD_BINARY_NAME", "argocd") + }). + Path("guestbook-symlink-folder"). + When(). + CreateApp(). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(HealthIs(health.HealthStatusHealthy)) +} 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/deployment_test.go b/test/e2e/deployment_test.go index 085ecee244ba2..20e79c2aff56c 100644 --- a/test/e2e/deployment_test.go +++ b/test/e2e/deployment_test.go @@ -1,12 +1,22 @@ package e2e import ( + "context" + "encoding/json" "fmt" + "os" "testing" + "time" "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/clientcmd" + "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/util/argo" + "github.com/argoproj/argo-cd/v2/util/clusterauth" "github.com/argoproj/gitops-engine/pkg/health" . "github.com/argoproj/gitops-engine/pkg/sync/common" @@ -108,3 +118,304 @@ func TestDeploymentWithoutTrackingMode(t *testing.T) { `, ctx.AppName())) }) } + +// This test verifies that Argo CD can: +// A) Deploy to a cluster where the URL of the cluster contains a query parameter: e.g. https://(kubernetes-url):443/?context=some-val +// and +// B) Multiple users can deploy to the same K8s cluster, using above mechanism (but with different Argo CD Cluster Secrets, and different ServiceAccounts) +func TestDeployToKubernetesAPIURLWithQueryParameter(t *testing.T) { + + // We test with both a cluster-scoped, and a non-cluster scoped, Argo CD Cluster Secret. + clusterScopedParam := []bool{false, true} + for _, clusterScoped := range clusterScopedParam { + + EnsureCleanState(t) + + // Simulate two users, each with their own Argo CD cluster secret that can only deploy to their Namespace + users := []string{E2ETestPrefix + "user1", E2ETestPrefix + "user2"} + + for _, username := range users { + createNamespaceScopedUser(t, username, clusterScoped) + + GivenWithSameState(t). + Name("e2e-test-app-"+username). + Path("deployment"). + When(). + CreateWithNoNameSpace("--dest-namespace", username). + Sync(). + Then(). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(HealthIs(health.HealthStatusHealthy)) + } + + } + +} + +// This test verifies that Argo CD can: +// When multiple Argo CD cluster secrets used to deploy to the same cluster (using query parameters), that the ServiceAccount RBAC +// fully enforces user boundary. +// Our simulated user's ServiceAccounts should not be able to deploy into a namespace that is outside that SA's RBAC. +func TestArgoCDSupportsMultipleServiceAccountsWithDifferingRBACOnSameCluster(t *testing.T) { + + // We test with both a cluster-scoped, and a non-cluster scoped, Argo CD Cluster Secret. + clusterScopedParam := []bool{ /*false,*/ true} + + for _, clusterScoped := range clusterScopedParam { + + EnsureCleanState(t) + + // Simulate two users, each with their own Argo CD cluster secret that can only deploy to their Namespace + users := []string{E2ETestPrefix + "user1", E2ETestPrefix + "user2"} + + for _, username := range users { + createNamespaceScopedUser(t, username, clusterScoped) + } + + for idx, username := range users { + + // we should use user-a's serviceaccount to deploy to user-b's namespace, and vice versa + // - If everything as working as expected, this should fail. + otherUser := users[(idx+1)%len(users)] + + // e.g. Attempt to deploy to user1's namespace, with user2's cluster Secret. This should fail, as user2's cluster Secret does not have the requisite permissions. + consequences := GivenWithSameState(t). + Name("e2e-test-app-"+username). + DestName(E2ETestPrefix+"cluster-"+otherUser). + Path("deployment"). + When(). + CreateWithNoNameSpace("--dest-namespace", username).IgnoreErrors(). + Sync().Then() + + // The error message differs based on whether the Argo CD Cluster Secret is namespace-scoped or cluster-scoped, but the idea is the same: + // - Even when deploying to the same cluster using 2 separate ServiceAccounts, the RBAC of those ServiceAccounts should continue to fully enforce RBAC boundaries. + + if !clusterScoped { + consequences.Expect(Condition(ApplicationConditionComparisonError, "Namespace \""+username+"\" for Deployment \"nginx-deployment\" is not managed")) + } else { + consequences.Expect(OperationMessageContains("User \"system:serviceaccount:" + otherUser + ":" + otherUser + "-serviceaccount\" cannot create resource \"deployments\" in API group \"apps\" in the namespace \"" + username + "\"")) + } + } + + } +} + +// generateReadOnlyClusterRoleandBindingForServiceAccount creates a ClusterRole/Binding that allows a ServiceAccount in a given namespace to read all resources on a cluster. +// - This allows the ServiceAccount to be used within a cluster-scoped Argo CD Cluster Secret +func generateReadOnlyClusterRoleandBindingForServiceAccount(roleSuffix string, serviceAccountNS string) (rbacv1.ClusterRole, rbacv1.ClusterRoleBinding) { + + clusterRole := rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: E2ETestPrefix + "read-all-" + roleSuffix, + }, + Rules: []rbacv1.PolicyRule{{ + Verbs: []string{"get", "list", "watch"}, + Resources: []string{"*"}, + APIGroups: []string{"*"}, + }}, + } + + clusterRoleBinding := rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: E2ETestPrefix + "read-all-" + roleSuffix, + }, + Subjects: []rbacv1.Subject{{ + Kind: rbacv1.ServiceAccountKind, + Namespace: serviceAccountNS, + Name: roleSuffix + "-serviceaccount", + }}, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: clusterRole.Name, + }, + } + + return clusterRole, clusterRoleBinding +} + +// buildArgoCDClusterSecret build (but does not create) an Argo CD Cluster Secret object with the given values +func buildArgoCDClusterSecret(secretName, secretNamespace, clusterName, clusterServer, clusterConfigJSON, clusterResources, clusterNamespaces string) corev1.Secret { + res := corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secretName, + Namespace: secretNamespace, + Labels: map[string]string{ + common.LabelKeySecretType: common.LabelValueSecretTypeCluster, + }, + }, + Data: map[string][]byte{ + "name": ([]byte)(clusterName), + "server": ([]byte)(clusterServer), + "config": ([]byte)(string(clusterConfigJSON)), + }, + } + + if clusterResources != "" { + res.Data["clusterResources"] = ([]byte)(clusterResources) + } + + if clusterNamespaces != "" { + res.Data["namespaces"] = ([]byte)(clusterNamespaces) + } + + return res +} + +// createNamespaceScopedUser +// - username = name of Namespace the simulated user is able to deploy to +// - clusterScopedSecrets = whether the Service Account is namespace-scoped or cluster-scoped. +func createNamespaceScopedUser(t *testing.T, username string, clusterScopedSecrets bool) { + + // Create a new Namespace for our simulated user + ns := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: username, + }, + } + _, err := KubeClientset.CoreV1().Namespaces().Create(context.Background(), &ns, metav1.CreateOptions{}) + assert.Nil(t, err) + + // Create a ServiceAccount in that Namespace, which will be used for the Argo CD Cluster SEcret + serviceAccountName := username + "-serviceaccount" + err = clusterauth.CreateServiceAccount(KubeClientset, serviceAccountName, ns.Name) + assert.Nil(t, err) + + // Create a Role that allows the ServiceAccount to read/write all within the Namespace + role := rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: E2ETestPrefix + "allow-all", + Namespace: ns.Name, + }, + Rules: []rbacv1.PolicyRule{{ + Verbs: []string{"*"}, + Resources: []string{"*"}, + APIGroups: []string{"*"}, + }}, + } + _, err = KubeClientset.RbacV1().Roles(role.Namespace).Create(context.Background(), &role, metav1.CreateOptions{}) + assert.Nil(t, err) + + // Bind the Role with the ServiceAccount in the Namespace + roleBinding := rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: E2ETestPrefix + "allow-all-binding", + Namespace: ns.Name, + }, + Subjects: []rbacv1.Subject{{ + Kind: rbacv1.ServiceAccountKind, + Name: serviceAccountName, + Namespace: ns.Name, + }}, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: role.Name, + }, + } + _, err = KubeClientset.RbacV1().RoleBindings(roleBinding.Namespace).Create(context.Background(), &roleBinding, metav1.CreateOptions{}) + assert.Nil(t, err) + + // Retrieve the bearer token from the ServiceAccount + token, err := clusterauth.GetServiceAccountBearerToken(KubeClientset, ns.Name, serviceAccountName, time.Second*60) + assert.Nil(t, err) + assert.NotEmpty(t, token) + + // In order to test a cluster-scoped Argo CD Cluster Secret, we may optionally grant the ServiceAccount read-all permissions at cluster scope. + if clusterScopedSecrets { + clusterRole, clusterRoleBinding := generateReadOnlyClusterRoleandBindingForServiceAccount(username, username) + + _, err := KubeClientset.RbacV1().ClusterRoles().Create(context.Background(), &clusterRole, metav1.CreateOptions{}) + assert.Nil(t, err) + + _, err = KubeClientset.RbacV1().ClusterRoleBindings().Create(context.Background(), &clusterRoleBinding, metav1.CreateOptions{}) + assert.Nil(t, err) + + } + + // Build the Argo CD Cluster Secret by using the service account token, and extracting needed values from kube config + clusterSecretConfigJSON := ClusterConfig{ + BearerToken: token, + TLSClientConfig: TLSClientConfig{ + Insecure: true, + }, + } + + jsonStringBytes, err := json.Marshal(clusterSecretConfigJSON) + assert.Nil(t, err) + + _, apiURL, err := extractKubeConfigValues() + assert.Nil(t, err) + + clusterResourcesField := "" + namespacesField := "" + + if !clusterScopedSecrets { + clusterResourcesField = "false" + namespacesField = ns.Name + } + + // We create an Argo CD cluster Secret declaratively, using the K8s client, rather than via CLI, as the CLI doesn't currently + // support Kubernetes API server URLs with query parameters. + + secret := buildArgoCDClusterSecret("test-"+username, ArgoCDNamespace, E2ETestPrefix+"cluster-"+username, apiURL+"?user="+username, + string(jsonStringBytes), clusterResourcesField, namespacesField) + + // Finally, create the Cluster secret in the Argo CD E2E namespace + _, err = KubeClientset.CoreV1().Secrets(secret.Namespace).Create(context.Background(), &secret, metav1.CreateOptions{}) + assert.Nil(t, err) +} + +// extractKubeConfigValues returns contents of the local environment's kubeconfig, using standard path resolution mechanism. +// Returns: +// - contents of kubeconfig +// - server name (within the kubeconfig) +// - error +func extractKubeConfigValues() (string, string, error) { + + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + + config, err := loadingRules.Load() + if err != nil { + return "", "", err + } + + context, ok := config.Contexts[config.CurrentContext] + if !ok || context == nil { + return "", "", fmt.Errorf("no context") + } + + cluster, ok := config.Clusters[context.Cluster] + if !ok || cluster == nil { + return "", "", fmt.Errorf("no cluster") + } + + var kubeConfigDefault string + + paths := loadingRules.Precedence + { + + // For all the kubeconfig paths, look for one that exists + for _, path := range paths { + _, err = os.Stat(path) + if err == nil { + // Success + kubeConfigDefault = path + break + } // Otherwise, continue. + + } + + if kubeConfigDefault == "" { + return "", "", fmt.Errorf("unable to retrieve kube config path") + } + } + + kubeConfigContents, err := os.ReadFile(kubeConfigDefault) + if err != nil { + return "", "", err + } + + return string(kubeConfigContents), cluster.Server, nil +} diff --git a/test/e2e/fixture/account/actions.go b/test/e2e/fixture/account/actions.go index 75e8762e76c91..f5708c5606a41 100644 --- a/test/e2e/fixture/account/actions.go +++ b/test/e2e/fixture/account/actions.go @@ -41,7 +41,7 @@ func (a *Actions) DoNotIgnoreErrors() *Actions { func (a *Actions) prepareSetPasswordArgs(account string) []string { a.context.t.Helper() return []string{ - "account", "update-password", "--account", account, "--current-password", fixture.AdminPassword, "--new-password", fixture.DefaultTestUserPassword, "--plaintext", + "account", "update-password", "--account", account, "--current-password", fixture.AdminPassword, "--new-password", fixture.DefaultTestUserPassword, } } diff --git a/test/e2e/fixture/app/actions.go b/test/e2e/fixture/app/actions.go index c8df055f1b8ac..a2b1d5e01371b 100644 --- a/test/e2e/fixture/app/actions.go +++ b/test/e2e/fixture/app/actions.go @@ -1,12 +1,14 @@ package app import ( + "encoding/json" "fmt" "os" log "github.com/sirupsen/logrus" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + client "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" . "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/util/errors" @@ -64,6 +66,24 @@ func (a *Actions) AddSignedFile(fileName, fileContents string) *Actions { return a } +func (a *Actions) AddSignedTag(name string) *Actions { + a.context.t.Helper() + fixture.AddSignedTag(name) + return a +} + +func (a *Actions) AddTag(name string) *Actions { + a.context.t.Helper() + fixture.AddTag(name) + return a +} + +func (a *Actions) RemoveSubmodule() *Actions { + a.context.t.Helper() + fixture.RemoveSubmodule() + return a +} + func (a *Actions) CreateFromPartialFile(data string, flags ...string) *Actions { a.context.t.Helper() tmpFile, err := os.CreateTemp("", "") @@ -259,7 +279,7 @@ func (a *Actions) Declarative(filename string) *Actions { func (a *Actions) DeclarativeWithCustomRepo(filename string, repoURL string) *Actions { a.context.t.Helper() values := map[string]interface{}{ - "ArgoCDNamespace": fixture.ArgoCDNamespace, + "ArgoCDNamespace": fixture.TestNamespace(), "DeploymentNamespace": fixture.DeploymentNamespace(), "Name": a.context.AppName(), "Path": a.context.path, @@ -277,6 +297,28 @@ func (a *Actions) PatchApp(patch string) *Actions { return a } +func (a *Actions) PatchAppHttp(patch string) *Actions { + a.context.t.Helper() + var application Application + var patchType = "merge" + var appName = a.context.AppQualifiedName() + var appNamespace = a.context.AppNamespace() + patchRequest := &client.ApplicationPatchRequest{ + Name: &appName, + PatchType: &patchType, + Patch: &patch, + AppNamespace: &appNamespace, + } + jsonBytes, err := json.MarshalIndent(patchRequest, "", " ") + errors.CheckError(err) + err = fixture.DoHttpJsonRequest("PATCH", + fmt.Sprintf("/api/v1/applications/%v", appName), + &application, + jsonBytes...) + errors.CheckError(err) + return a +} + func (a *Actions) AppSet(flags ...string) *Actions { a.context.t.Helper() args := []string{"app", "set", a.context.AppQualifiedName()} @@ -324,6 +366,10 @@ func (a *Actions) Sync(args ...string) *Actions { args = append(args, "--force") } + if a.context.applyOutOfSyncOnly { + args = append(args, "--apply-out-of-sync-only") + } + if a.context.replace { args = append(args, "--replace") } @@ -353,6 +399,12 @@ func (a *Actions) Refresh(refreshType RefreshType) *Actions { return a } +func (a *Actions) Get() *Actions { + a.context.t.Helper() + a.runCli("app", "get", a.context.AppQualifiedName()) + return a +} + func (a *Actions) Delete(cascade bool) *Actions { a.context.t.Helper() a.runCli("app", "delete", a.context.AppQualifiedName(), fmt.Sprintf("--cascade=%v", cascade), "--yes") @@ -365,6 +417,23 @@ func (a *Actions) DeleteBySelector(selector string) *Actions { return a } +func (a *Actions) DeleteBySelectorWithWait(selector string) *Actions { + a.context.t.Helper() + a.runCli("app", "delete", fmt.Sprintf("--selector=%s", selector), "--yes", "--wait") + return a +} + +func (a *Actions) Wait(args ...string) *Actions { + a.context.t.Helper() + args = append([]string{"app", "wait"}, args...) + if a.context.name != "" { + args = append(args, a.context.AppQualifiedName()) + } + args = append(args, "--timeout", fmt.Sprintf("%v", a.context.timeout)) + a.runCli(args...) + return a +} + func (a *Actions) SetParamInSettingConfigMap(key, value string) *Actions { fixture.SetParamInSettingConfigMap(key, value) return a diff --git a/test/e2e/fixture/app/consequences.go b/test/e2e/fixture/app/consequences.go index f5d9240024951..9ee99fec6ca6d 100644 --- a/test/e2e/fixture/app/consequences.go +++ b/test/e2e/fixture/app/consequences.go @@ -86,11 +86,6 @@ func (c *Consequences) resource(kind, name, namespace string) ResourceStatus { } } -func (c *Consequences) Timeout(timeout int) *Consequences { - c.timeout = timeout - return c -} - func (c *Consequences) AndCLIOutput(block func(output string, err error)) *Consequences { c.context.t.Helper() block(c.actions.lastOutput, c.actions.lastError) diff --git a/test/e2e/fixture/app/context.go b/test/e2e/fixture/app/context.go index 0aa94a33ac906..41c8dbd17bcad 100644 --- a/test/e2e/fixture/app/context.go +++ b/test/e2e/fixture/app/context.go @@ -38,6 +38,7 @@ type Context struct { project string revision string force bool + applyOutOfSyncOnly bool directoryRecurse bool replace bool helmPassCredentials bool @@ -50,8 +51,8 @@ type ContextArgs struct { AppNamespace string } -func Given(t *testing.T) *Context { - fixture.EnsureCleanState(t) +func Given(t *testing.T, opts ...fixture.TestOption) *Context { + fixture.EnsureCleanState(t, opts...) return GivenWithSameState(t) } @@ -64,7 +65,7 @@ func GivenWithNamespace(t *testing.T, namespace string) *Context { func GivenWithSameState(t *testing.T) *Context { // ARGOCE_E2E_DEFAULT_TIMEOUT can be used to override the default timeout // for any context. - timeout := env.ParseNumFromEnv("ARGOCD_E2E_DEFAULT_TIMEOUT", 10, 0, 180) + timeout := env.ParseNumFromEnv("ARGOCD_E2E_DEFAULT_TIMEOUT", 20, 0, 180) return &Context{ t: t, destServer: v1alpha1.KubernetesInternalAPIServerAddr, @@ -300,13 +301,6 @@ func (c *Context) ResourceFilter(filter settings.ResourcesFilter) *Context { return c } -// this both configures the plugin, but forces use of it -func (c *Context) ConfigManagementPlugin(plugin v1alpha1.ConfigManagementPlugin) *Context { - fixture.SetConfigManagementPlugins(plugin) - c.configManagementPlugin = plugin.Name - return c -} - func (c *Context) And(block func()) *Context { block() return c @@ -348,6 +342,11 @@ func (c *Context) Force() *Context { return c } +func (c *Context) ApplyOutOfSyncOnly() *Context { + c.applyOutOfSyncOnly = true + return c +} + func (c *Context) HelmPassCredentials() *Context { c.helmPassCredentials = true return c diff --git a/test/e2e/fixture/app/expectation.go b/test/e2e/fixture/app/expectation.go index 14f978c84a402..4d4918e981751 100644 --- a/test/e2e/fixture/app/expectation.go +++ b/test/e2e/fixture/app/expectation.go @@ -3,6 +3,7 @@ package app import ( "context" "fmt" + "reflect" "regexp" "strings" @@ -87,6 +88,26 @@ func NoConditions() Expectation { } } +func NoStatus() Expectation { + return func(c *Consequences) (state, string) { + message := "no status" + if reflect.ValueOf(c.app().Status).IsZero() { + return succeeded, message + } + return pending, message + } +} + +func StatusExists() Expectation { + return func(c *Consequences) (state, string) { + message := "status exists" + if !reflect.ValueOf(c.app().Status).IsZero() { + return succeeded, message + } + return pending, message + } +} + func Namespace(name string, block func(app *Application, ns *v1.Namespace)) Expectation { return func(c *Consequences) (state, string) { ns, err := namespace(name) @@ -195,6 +216,19 @@ func DoesNotExist() Expectation { } } +func DoesNotExistNow() Expectation { + return func(c *Consequences) (state, string) { + _, err := c.get() + if err != nil { + if apierr.IsNotFound(err) { + return succeeded, "app does not exist" + } + return failed, err.Error() + } + return failed, "app should not exist" + } +} + func Pod(predicate func(p v1.Pod) bool) Expectation { return func(c *Consequences) (state, string) { pods, err := pods() @@ -271,20 +305,31 @@ func event(namespace string, reason string, message string) Expectation { } func Event(reason string, message string) Expectation { - return event(fixture.ArgoCDNamespace, reason, message) + return event(fixture.TestNamespace(), reason, message) } func NamespacedEvent(namespace string, reason string, message string) Expectation { return event(namespace, reason, message) } -// asserts that the last command was successful -func Success(message string) Expectation { +// Success asserts that the last command was successful and that the output contains the given message. +func Success(message string, matchers ...func(string, string) bool) Expectation { + if len(matchers) == 0 { + matchers = append(matchers, strings.Contains) + } + match := func(actual, expected string) bool { + for i := range matchers { + if !matchers[i](actual, expected) { + return false + } + } + return true + } return func(c *Consequences) (state, string) { if c.actions.lastError != nil { return failed, "error" } - if !strings.Contains(c.actions.lastOutput, message) { + if !match(c.actions.lastOutput, message) { return failed, fmt.Sprintf("output did not contain '%s'", message) } return succeeded, fmt.Sprintf("no error and output contained '%s'", message) @@ -324,3 +369,10 @@ func ErrorRegex(messagePattern, err string) Expectation { return regexp.MustCompile(expected).MatchString(actual) }) } + +// SuccessRegex asserts that the last command was successful and output matches given regex expression +func SuccessRegex(messagePattern string) Expectation { + return Success(messagePattern, func(actual, expected string) bool { + return regexp.MustCompile(expected).MatchString(actual) + }) +} diff --git a/test/e2e/fixture/applicationsets/actions.go b/test/e2e/fixture/applicationsets/actions.go index 13198890e0efe..0b167c2b1a734 100644 --- a/test/e2e/fixture/applicationsets/actions.go +++ b/test/e2e/fixture/applicationsets/actions.go @@ -7,6 +7,8 @@ import ( "strings" "time" + "github.com/argoproj/argo-cd/v2/test/e2e/fixture" + log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" v1 "k8s.io/api/rbac/v1" @@ -14,9 +16,9 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/dynamic" "github.com/argoproj/argo-cd/v2/common" - argocommon "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets/utils" "github.com/argoproj/argo-cd/v2/util/clusterauth" @@ -62,6 +64,18 @@ func (a *Actions) Then() *Consequences { return &Consequences{a.context, a} } +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.switchToNamespace = "" + log.Infof("switched to argocd namespace: %s", utils.ArgoCDNamespace) + return a +} + // CreateClusterSecret creates a faux cluster secret, with the given cluster server and cluster name (this cluster // will not actually be used by the Argo CD controller, but that's not needed for our E2E tests) func (a *Actions) CreateClusterSecret(secretName string, clusterName string, clusterServer string) *Actions { @@ -73,7 +87,7 @@ func (a *Actions) CreateClusterSecret(secretName string, clusterName string, clu // Look for a service account matching '*application-controller*' err := wait.Poll(500*time.Millisecond, 30*time.Second, func() (bool, error) { - serviceAccountList, err := fixtureClient.KubeClientset.CoreV1().ServiceAccounts(utils.ArgoCDNamespace).List(context.Background(), metav1.ListOptions{}) + serviceAccountList, err := fixtureClient.KubeClientset.CoreV1().ServiceAccounts(fixture.TestNamespace()).List(context.Background(), metav1.ListOptions{}) if err != nil { fmt.Println("Unable to retrieve ServiceAccount list", err) return false, nil @@ -100,16 +114,16 @@ func (a *Actions) CreateClusterSecret(secretName string, clusterName string, clu if err == nil { var bearerToken string - bearerToken, err = clusterauth.GetServiceAccountBearerToken(fixtureClient.KubeClientset, utils.ArgoCDNamespace, serviceAccountName, common.BearerTokenTimeout) + bearerToken, err = clusterauth.GetServiceAccountBearerToken(fixtureClient.KubeClientset, fixture.TestNamespace(), serviceAccountName, common.BearerTokenTimeout) // bearerToken secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: secretName, - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Labels: map[string]string{ - argocommon.LabelKeySecretType: argocommon.LabelValueSecretTypeCluster, - utils.TestingLabel: "true", + common.LabelKeySecretType: common.LabelValueSecretTypeCluster, + utils.TestingLabel: "true", }, }, Data: map[string][]byte{ @@ -141,7 +155,7 @@ func (a *Actions) CreateClusterSecret(secretName string, clusterName string, clu // DeleteClusterSecret deletes a faux cluster secret func (a *Actions) DeleteClusterSecret(secretName string) *Actions { - err := utils.GetE2EFixtureK8sClient().KubeClientset.CoreV1().Secrets(utils.ArgoCDNamespace).Delete(context.Background(), secretName, metav1.DeleteOptions{}) + err := utils.GetE2EFixtureK8sClient().KubeClientset.CoreV1().Secrets(fixture.TestNamespace()).Delete(context.Background(), secretName, metav1.DeleteOptions{}) a.describeAction = fmt.Sprintf("deleting cluster Secret '%s'", secretName) a.lastOutput, a.lastError = "", err @@ -153,7 +167,7 @@ func (a *Actions) DeleteClusterSecret(secretName string) *Actions { // DeleteConfigMap deletes a faux cluster secret func (a *Actions) DeleteConfigMap(configMapName string) *Actions { - err := utils.GetE2EFixtureK8sClient().KubeClientset.CoreV1().ConfigMaps(utils.ArgoCDNamespace).Delete(context.Background(), configMapName, metav1.DeleteOptions{}) + err := utils.GetE2EFixtureK8sClient().KubeClientset.CoreV1().ConfigMaps(fixture.TestNamespace()).Delete(context.Background(), configMapName, metav1.DeleteOptions{}) a.describeAction = fmt.Sprintf("deleting configMap '%s'", configMapName) a.lastOutput, a.lastError = "", err @@ -165,7 +179,7 @@ func (a *Actions) DeleteConfigMap(configMapName string) *Actions { // DeletePlacementDecision deletes a faux cluster secret func (a *Actions) DeletePlacementDecision(placementDecisionName string) *Actions { - err := utils.GetE2EFixtureK8sClient().DynamicClientset.Resource(pdGVR).Namespace(utils.ArgoCDNamespace).Delete(context.Background(), placementDecisionName, metav1.DeleteOptions{}) + err := utils.GetE2EFixtureK8sClient().DynamicClientset.Resource(pdGVR).Namespace(fixture.TestNamespace()).Delete(context.Background(), placementDecisionName, metav1.DeleteOptions{}) a.describeAction = fmt.Sprintf("deleting placement decision '%s'", placementDecisionName) a.lastOutput, a.lastError = "", err @@ -176,15 +190,15 @@ func (a *Actions) DeletePlacementDecision(placementDecisionName string) *Actions // Create a temporary namespace, from utils.ApplicationSet, for use by the test. // This namespace will be deleted on subsequent tests. -func (a *Actions) CreateNamespace() *Actions { +func (a *Actions) CreateNamespace(namespace string) *Actions { a.context.t.Helper() fixtureClient := utils.GetE2EFixtureK8sClient() _, err := fixtureClient.KubeClientset.CoreV1().Namespaces().Create(context.Background(), - &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: utils.ApplicationSetNamespace}}, metav1.CreateOptions{}) + &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}, metav1.CreateOptions{}) - a.describeAction = fmt.Sprintf("creating namespace '%s'", utils.ApplicationSetNamespace) + a.describeAction = fmt.Sprintf("creating namespace '%s'", namespace) a.lastOutput, a.lastError = "", err a.verifyAction() @@ -195,17 +209,32 @@ func (a *Actions) CreateNamespace() *Actions { func (a *Actions) Create(appSet v1alpha1.ApplicationSet) *Actions { a.context.t.Helper() + fixtureClient := utils.GetE2EFixtureK8sClient() + appSet.APIVersion = "argoproj.io/v1alpha1" appSet.Kind = "ApplicationSet" - fixtureClient := utils.GetE2EFixtureK8sClient() - newResource, err := fixtureClient.AppSetClientset.Create(context.Background(), utils.MustToUnstructured(&appSet), metav1.CreateOptions{}) + var appSetClientSet dynamic.ResourceInterface + + 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 + } + + newResource, err := appSetClientSet.Create(context.Background(), utils.MustToUnstructured(&appSet), metav1.CreateOptions{}) if err == nil { a.context.name = newResource.GetName() + a.context.namespace = newResource.GetNamespace() } - a.describeAction = fmt.Sprintf("creating ApplicationSet '%s'", appSet.Name) + a.describeAction = fmt.Sprintf("creating ApplicationSet '%s/%s'", appSet.Namespace, appSet.Name) a.lastOutput, a.lastError = "", err a.verifyAction() @@ -218,8 +247,8 @@ func (a *Actions) CreatePlacementRoleAndRoleBinding() *Actions { var err error - _, err = fixtureClient.KubeClientset.RbacV1().Roles(utils.ArgoCDNamespace).Create(context.Background(), &v1.Role{ - ObjectMeta: metav1.ObjectMeta{Name: "placement-role", Namespace: utils.ArgoCDNamespace}, + _, err = fixtureClient.KubeClientset.RbacV1().Roles(fixture.TestNamespace()).Create(context.Background(), &v1.Role{ + ObjectMeta: metav1.ObjectMeta{Name: "placement-role", Namespace: fixture.TestNamespace()}, Rules: []v1.PolicyRule{ { Verbs: []string{"get", "list", "watch"}, @@ -233,13 +262,13 @@ func (a *Actions) CreatePlacementRoleAndRoleBinding() *Actions { } if err == nil { - _, err = fixtureClient.KubeClientset.RbacV1().RoleBindings(utils.ArgoCDNamespace).Create(context.Background(), + _, err = fixtureClient.KubeClientset.RbacV1().RoleBindings(fixture.TestNamespace()).Create(context.Background(), &v1.RoleBinding{ - ObjectMeta: metav1.ObjectMeta{Name: "placement-role-binding", Namespace: utils.ArgoCDNamespace}, + ObjectMeta: metav1.ObjectMeta{Name: "placement-role-binding", Namespace: fixture.TestNamespace()}, Subjects: []v1.Subject{ { Name: "argocd-applicationset-controller", - Namespace: utils.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), Kind: "ServiceAccount", }, }, @@ -267,14 +296,14 @@ func (a *Actions) CreatePlacementDecisionConfigMap(configMapName string) *Action fixtureClient := utils.GetE2EFixtureK8sClient() - _, err := fixtureClient.KubeClientset.CoreV1().ConfigMaps(utils.ArgoCDNamespace).Get(context.Background(), configMapName, metav1.GetOptions{}) + _, err := fixtureClient.KubeClientset.CoreV1().ConfigMaps(fixture.TestNamespace()).Get(context.Background(), configMapName, metav1.GetOptions{}) // Don't do anything if it exists if err == nil { return a } - _, err = fixtureClient.KubeClientset.CoreV1().ConfigMaps(utils.ArgoCDNamespace).Create(context.Background(), + _, err = fixtureClient.KubeClientset.CoreV1().ConfigMaps(fixture.TestNamespace()).Create(context.Background(), &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: configMapName, @@ -299,7 +328,7 @@ func (a *Actions) CreatePlacementDecision(placementDecisionName string) *Actions fixtureClient := utils.GetE2EFixtureK8sClient().DynamicClientset - _, err := fixtureClient.Resource(pdGVR).Namespace(utils.ArgoCDNamespace).Get( + _, err := fixtureClient.Resource(pdGVR).Namespace(fixture.TestNamespace()).Get( context.Background(), placementDecisionName, metav1.GetOptions{}) @@ -312,7 +341,7 @@ func (a *Actions) CreatePlacementDecision(placementDecisionName string) *Actions Object: map[string]interface{}{ "metadata": map[string]interface{}{ "name": placementDecisionName, - "namespace": utils.ArgoCDNamespace, + "namespace": fixture.TestNamespace(), }, "kind": "PlacementDecision", "apiVersion": "cluster.open-cluster-management.io/v1alpha1", @@ -320,7 +349,7 @@ func (a *Actions) CreatePlacementDecision(placementDecisionName string) *Actions }, } - _, err = fixtureClient.Resource(pdGVR).Namespace(utils.ArgoCDNamespace).Create( + _, err = fixtureClient.Resource(pdGVR).Namespace(fixture.TestNamespace()).Create( context.Background(), placementDecision, metav1.CreateOptions{}) @@ -336,7 +365,7 @@ func (a *Actions) StatusUpdatePlacementDecision(placementDecisionName string, cl a.context.t.Helper() fixtureClient := utils.GetE2EFixtureK8sClient().DynamicClientset - placementDecision, err := fixtureClient.Resource(pdGVR).Namespace(utils.ArgoCDNamespace).Get( + placementDecision, err := fixtureClient.Resource(pdGVR).Namespace(fixture.TestNamespace()).Get( context.Background(), placementDecisionName, metav1.GetOptions{}) @@ -346,7 +375,7 @@ func (a *Actions) StatusUpdatePlacementDecision(placementDecisionName string, cl } if err == nil { - _, err = fixtureClient.Resource(pdGVR).Namespace(utils.ArgoCDNamespace).UpdateStatus( + _, err = fixtureClient.Resource(pdGVR).Namespace(fixture.TestNamespace()).UpdateStatus( context.Background(), placementDecision, metav1.UpdateOptions{}) @@ -364,9 +393,22 @@ func (a *Actions) Delete() *Actions { fixtureClient := utils.GetE2EFixtureK8sClient() + var appSetClientSet dynamic.ResourceInterface + + 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 + } + deleteProp := metav1.DeletePropagationForeground - err := fixtureClient.AppSetClientset.Delete(context.Background(), a.context.name, metav1.DeleteOptions{PropagationPolicy: &deleteProp}) - a.describeAction = fmt.Sprintf("Deleting ApplicationSet '%s' %v", a.context.name, err) + err := appSetClientSet.Delete(context.Background(), a.context.name, metav1.DeleteOptions{PropagationPolicy: &deleteProp}) + a.describeAction = fmt.Sprintf("Deleting ApplicationSet '%s/%s' %v", a.context.namespace, a.context.name, err) a.lastOutput, a.lastError = "", err a.verifyAction() @@ -378,7 +420,20 @@ func (a *Actions) get() (*v1alpha1.ApplicationSet, error) { appSet := v1alpha1.ApplicationSet{} fixtureClient := utils.GetE2EFixtureK8sClient() - newResource, err := fixtureClient.AppSetClientset.Get(context.Background(), a.context.name, metav1.GetOptions{}) + + var appSetClientSet dynamic.ResourceInterface + + 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 + } + + newResource, err := appSetClientSet.Get(context.Background(), a.context.name, metav1.GetOptions{}) if err != nil { return nil, err } @@ -413,10 +468,24 @@ func (a *Actions) Update(toUpdate func(*v1alpha1.ApplicationSet)) *Actions { if err == nil { // Keep trying to update until it succeeds, or the test times out toUpdate(appSet) - a.describeAction = fmt.Sprintf("updating ApplicationSet '%s'", appSet.Name) + a.describeAction = fmt.Sprintf("updating ApplicationSet '%s/%s'", appSet.Namespace, appSet.Name) fixtureClient := utils.GetE2EFixtureK8sClient() - _, err = fixtureClient.AppSetClientset.Update(context.Background(), utils.MustToUnstructured(&appSet), metav1.UpdateOptions{}) + + var appSetClientSet dynamic.ResourceInterface + + 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 + } + + _, err = appSetClientSet.Update(context.Background(), utils.MustToUnstructured(&appSet), metav1.UpdateOptions{}) if err != nil { mostRecentError = err @@ -444,5 +513,18 @@ func (a *Actions) verifyAction() { if !a.ignoreErrors { a.Then().Expect(Success("")) } +} + +func (a *Actions) AppSet(appName string, flags ...string) *Actions { + a.context.t.Helper() + args := []string{"app", "set", appName} + args = append(args, flags...) + a.runCli(args...) + return a +} +func (a *Actions) runCli(args ...string) { + a.context.t.Helper() + a.lastOutput, a.lastError = fixture.RunCli(args...) + a.verifyAction() } diff --git a/test/e2e/fixture/applicationsets/consequences.go b/test/e2e/fixture/applicationsets/consequences.go index e5d45cdf29f2e..db614f3cf3075 100644 --- a/test/e2e/fixture/applicationsets/consequences.go +++ b/test/e2e/fixture/applicationsets/consequences.go @@ -5,12 +5,14 @@ import ( "encoding/json" "time" + "github.com/argoproj/argo-cd/v2/test/e2e/fixture" + "github.com/argoproj/pkg/errors" log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/dynamic" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets/utils" ) @@ -60,7 +62,7 @@ func (c *Consequences) When() *Actions { return c.actions } -func (c *Consequences) app(name string) *argov1alpha1.Application { +func (c *Consequences) app(name string) *v1alpha1.Application { apps := c.apps() for index, app := range apps { @@ -72,14 +74,21 @@ func (c *Consequences) app(name string) *argov1alpha1.Application { return nil } -func (c *Consequences) apps() []argov1alpha1.Application { +func (c *Consequences) apps() []v1alpha1.Application { + + var namespace string + if c.context.switchToNamespace != "" { + namespace = string(c.context.switchToNamespace) + } else { + namespace = fixture.TestNamespace() + } fixtureClient := utils.GetE2EFixtureK8sClient() - list, err := fixtureClient.AppClientset.ArgoprojV1alpha1().Applications(utils.ArgoCDNamespace).List(context.Background(), metav1.ListOptions{}) + list, err := fixtureClient.AppClientset.ArgoprojV1alpha1().Applications(namespace).List(context.Background(), metav1.ListOptions{}) errors.CheckError(err) if list == nil { - list = &argov1alpha1.ApplicationList{} + list = &v1alpha1.ApplicationList{} } return list.Items @@ -88,7 +97,16 @@ func (c *Consequences) apps() []argov1alpha1.Application { func (c *Consequences) applicationSet(applicationSetName string) *v1alpha1.ApplicationSet { fixtureClient := utils.GetE2EFixtureK8sClient() - list, err := fixtureClient.AppSetClientset.Get(context.Background(), c.actions.context.name, metav1.GetOptions{}) + + var appSetClientSet dynamic.ResourceInterface + + if c.context.switchToNamespace != "" { + appSetClientSet = fixtureClient.ExternalAppSetClientsets[c.context.switchToNamespace] + } else { + appSetClientSet = fixtureClient.AppSetClientset + } + + list, err := appSetClientSet.Get(context.Background(), c.actions.context.name, metav1.GetOptions{}) errors.CheckError(err) var appSet v1alpha1.ApplicationSet diff --git a/test/e2e/fixture/applicationsets/context.go b/test/e2e/fixture/applicationsets/context.go index c6269c4b36b61..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,11 +12,13 @@ type Context struct { t *testing.T // name is the ApplicationSet's name, created by a Create action - name string + 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/expectation.go b/test/e2e/fixture/applicationsets/expectation.go index e8be81b906d7e..990ad5f33dbfb 100644 --- a/test/e2e/fixture/applicationsets/expectation.go +++ b/test/e2e/fixture/applicationsets/expectation.go @@ -11,7 +11,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets/utils" ) @@ -58,13 +57,13 @@ func Error(message, err string) Expectation { // ApplicationsExist checks whether each of the 'expectedApps' exist in the namespace, and are // equivalent to provided values. -func ApplicationsExist(expectedApps []argov1alpha1.Application) Expectation { +func ApplicationsExist(expectedApps []v1alpha1.Application) Expectation { return func(c *Consequences) (state, string) { for _, expectedApp := range expectedApps { foundApp := c.app(expectedApp.Name) if foundApp == nil { - return pending, fmt.Sprintf("missing app '%s'", expectedApp.Name) + return pending, fmt.Sprintf("missing app '%s'", expectedApp.QualifiedName()) } if !appsAreEqual(expectedApp, *foundApp) { @@ -74,7 +73,7 @@ func ApplicationsExist(expectedApps []argov1alpha1.Application) Expectation { return failed, err.Error() } - return pending, fmt.Sprintf("apps are not equal: '%s', diff: %s\n", expectedApp.Name, diff) + return pending, fmt.Sprintf("apps are not equal: '%s', diff: %s\n", expectedApp.QualifiedName(), diff) } @@ -107,13 +106,13 @@ func ApplicationSetHasConditions(applicationSetName string, expectedConditions [ } // ApplicationsDoNotExist checks that each of the 'expectedApps' no longer exist in the namespace -func ApplicationsDoNotExist(expectedApps []argov1alpha1.Application) Expectation { +func ApplicationsDoNotExist(expectedApps []v1alpha1.Application) Expectation { return func(c *Consequences) (state, string) { for _, expectedApp := range expectedApps { foundApp := c.app(expectedApp.Name) if foundApp != nil { - return pending, fmt.Sprintf("app '%s' should no longer exist", expectedApp.Name) + return pending, fmt.Sprintf("app '%s' should no longer exist", expectedApp.QualifiedName()) } } @@ -124,7 +123,7 @@ func ApplicationsDoNotExist(expectedApps []argov1alpha1.Application) Expectation // Pod checks whether a specified condition is true for any of the pods in the namespace func Pod(predicate func(p corev1.Pod) bool) Expectation { return func(c *Consequences) (state, string) { - pods, err := pods(utils.ApplicationSetNamespace) + pods, err := pods(utils.ApplicationsResourcesNamespace) if err != nil { return failed, err.Error() } @@ -145,7 +144,7 @@ func pods(namespace string) (*corev1.PodList, error) { } // getDiff returns a string containing a comparison result of two applications (for test output/debug purposes) -func getDiff(orig, new argov1alpha1.Application) (string, error) { +func getDiff(orig, new v1alpha1.Application) (string, error) { bytes, _, err := diff.CreateTwoWayMergePatch(orig, new, orig) if err != nil { @@ -177,13 +176,13 @@ func getConditionDiff(orig, new []v1alpha1.ApplicationSetCondition) (string, err } // filterFields returns a copy of Application, but with unnecessary (for testing) fields removed -func filterFields(input argov1alpha1.Application) argov1alpha1.Application { +func filterFields(input v1alpha1.Application) v1alpha1.Application { spec := input.Spec metaCopy := input.ObjectMeta.DeepCopy() - output := argov1alpha1.Application{ + output := v1alpha1.Application{ ObjectMeta: metav1.ObjectMeta{ Labels: metaCopy.Labels, Annotations: metaCopy.Annotations, @@ -191,13 +190,13 @@ func filterFields(input argov1alpha1.Application) argov1alpha1.Application { Namespace: metaCopy.Namespace, Finalizers: metaCopy.Finalizers, }, - Spec: argov1alpha1.ApplicationSpec{ - Source: &argov1alpha1.ApplicationSource{ + Spec: v1alpha1.ApplicationSpec{ + Source: &v1alpha1.ApplicationSource{ Path: spec.GetSource().Path, RepoURL: spec.GetSource().RepoURL, TargetRevision: spec.GetSource().TargetRevision, }, - Destination: argov1alpha1.ApplicationDestination{ + Destination: v1alpha1.ApplicationDestination{ Server: spec.Destination.Server, Name: spec.Destination.Name, Namespace: spec.Destination.Namespace, @@ -227,7 +226,7 @@ func filterConditionFields(input *[]v1alpha1.ApplicationSetCondition) *[]v1alpha } // appsAreEqual returns true if the apps are equal, comparing only fields of interest -func appsAreEqual(one argov1alpha1.Application, two argov1alpha1.Application) bool { +func appsAreEqual(one v1alpha1.Application, two v1alpha1.Application) bool { return reflect.DeepEqual(filterFields(one), filterFields(two)) } diff --git a/test/e2e/fixture/applicationsets/utils/fixture.go b/test/e2e/fixture/applicationsets/utils/fixture.go index dc70ac2a02b4e..d4e23e5f5415d 100644 --- a/test/e2e/fixture/applicationsets/utils/fixture.go +++ b/test/e2e/fixture/applicationsets/utils/fixture.go @@ -13,8 +13,6 @@ import ( log "github.com/sirupsen/logrus" - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - "k8s.io/apimachinery/pkg/api/equality" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -24,18 +22,29 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + "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" - // ApplicationSetNamespace is the namespace into which temporary resources (such as Deployments/Pods/etc) + // ArgoCDExternalNamespace is an external namespace to test additional namespaces + 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. // Note: this is NOT the namespace the ApplicationSet controller is deployed to; see ArgoCDNamespace. - ApplicationSetNamespace = "applicationset-e2e" + ApplicationsResourcesNamespace = "applicationset-e2e" TmpDir = "/tmp/applicationset-e2e" TestingLabel = "e2e.argoproj.io" @@ -51,16 +60,30 @@ 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 + KubeClientset kubernetes.Interface + DynamicClientset dynamic.Interface + AppClientset appclientset.Interface + AppSetClientset dynamic.ResourceInterface + ExternalAppSetClientsets map[ExternalNamespace]dynamic.ResourceInterface +} + +func GetEnvWithDefault(envName, defaultValue string) string { + r := os.Getenv(envName) + if r == "" { + return defaultValue + } + return r +} + +// TestNamespace returns the namespace where Argo CD E2E test instance will be +// running in. +func TestNamespace() string { + return GetEnvWithDefault("ARGOCD_E2E_NAMESPACE", ArgoCDNamespace) } // GetE2EFixtureK8sClient initializes the Kubernetes clients (if needed), and returns the most recently initalized value. // Note: this requires a local Kubernetes configuration (for example, while running the E2E tests). func GetE2EFixtureK8sClient() *E2EFixtureK8sClient { - // Initialize the Kubernetes clients only on first use clientInitialized.Do(func() { @@ -73,13 +96,17 @@ func GetE2EFixtureK8sClient() *E2EFixtureK8sClient { KubeClientset: kubernetes.NewForConfigOrDie(config), } - internalClientVars.AppSetClientset = internalClientVars.DynamicClientset.Resource(v1alpha1.SchemeGroupVersion.WithResource("applicationsets")).Namespace(ArgoCDNamespace) + internalClientVars.AppSetClientset = internalClientVars.DynamicClientset.Resource(v1alpha1.SchemeGroupVersion.WithResource("applicationsets")).Namespace(TestNamespace()) + 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 } -// EnsureCleanSlate ensures that the Kubernetes resources on the cluster are are in a 'clean' state, before a test is run. +// EnsureCleanSlate ensures that the Kubernetes resources on the cluster are in a 'clean' state, before a test is run. func EnsureCleanState(t *testing.T) { start := time.Now() @@ -89,19 +116,31 @@ func EnsureCleanState(t *testing.T) { policy := v1.DeletePropagationForeground // Delete the applicationset-e2e namespace, if it exists - err := fixtureClient.KubeClientset.CoreV1().Namespaces().Delete(context.Background(), ApplicationSetNamespace, v1.DeleteOptions{PropagationPolicy: &policy}) + err := fixtureClient.KubeClientset.CoreV1().Namespaces().Delete(context.Background(), ApplicationsResourcesNamespace, v1.DeleteOptions{PropagationPolicy: &policy}) if err != nil && !strings.Contains(err.Error(), "not found") { // 'not found' error is expected CheckError(err) } + // Delete the argocd-e2e-external namespace, if it exists + 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(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 // kubectl delete applicationsets --all CheckError(fixtureClient.AppSetClientset.DeleteCollection(context.Background(), v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{})) // kubectl delete apps --all - CheckError(fixtureClient.AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).DeleteCollection(context.Background(), v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{})) + CheckError(fixtureClient.AppClientset.ArgoprojV1alpha1().Applications(TestNamespace()).DeleteCollection(context.Background(), v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{})) // kubectl delete secrets -l e2e.argoproj.io=true - CheckError(fixtureClient.KubeClientset.CoreV1().Secrets(ArgoCDNamespace).DeleteCollection(context.Background(), + CheckError(fixtureClient.KubeClientset.CoreV1().Secrets(TestNamespace()).DeleteCollection(context.Background(), v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{LabelSelector: TestingLabel + "=true"})) // First we wait up to 30 seconds for all the ApplicationSets to delete, but we don't fail if they don't. @@ -121,14 +160,14 @@ func EnsureCleanState(t *testing.T) { // Remove finalizers from Argo CD Application resources in the namespace err = waitForSuccess(func() error { - appList, err := fixtureClient.AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).List(context.Background(), v1.ListOptions{}) + appList, err := fixtureClient.AppClientset.ArgoprojV1alpha1().Applications(TestNamespace()).List(context.Background(), v1.ListOptions{}) if err != nil { return err } for _, app := range appList.Items { t.Log("Removing finalizer for: ", app.Name) app.Finalizers = []string{} - _, err := fixtureClient.AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Update(context.TODO(), &app, v1.UpdateOptions{}) + _, err := fixtureClient.AppClientset.ArgoprojV1alpha1().Applications(TestNamespace()).Update(context.TODO(), &app, v1.UpdateOptions{}) if err != nil { return err } @@ -145,12 +184,24 @@ func EnsureCleanState(t *testing.T) { // create tmp dir FailOnErr(Run("", "mkdir", "-p", TmpDir)) + // We can switch user and as result in previous state we will have non-admin user, this case should be reset + fixture.LoginAs("admin") + log.WithFields(log.Fields{"duration": time.Since(start), "name": t.Name(), "id": id, "username": "admin", "password": "password"}).Info("clean state") } 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{}) @@ -169,7 +220,7 @@ func waitForExpectedClusterState() error { // Wait up to 60 seconds for all the Applications to delete if err := waitForSuccess(func() error { - appList, err := fixtureClient.AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).List(context.Background(), v1.ListOptions{}) + appList, err := fixtureClient.AppClientset.ArgoprojV1alpha1().Applications(TestNamespace()).List(context.Background(), v1.ListOptions{}) if err != nil { return err } @@ -184,31 +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(), ApplicationSetNamespace, v1.GetOptions{}) + 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 + } + } - msg := "" + return nil +} - if err == nil { - msg = fmt.Sprintf("namespace '%s' still exists, after delete", ApplicationSetNamespace) - } +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 msg == "" && err != nil && strings.Contains(err.Error(), "not found") { - // Success is an error containing 'applicationset-e2e' not found. - return nil - } +func cleanUpNamespace(fixtureClient *E2EFixtureK8sClient, namespace string) error { + _, err := fixtureClient.KubeClientset.CoreV1().Namespaces().Get(context.Background(), namespace, v1.GetOptions{}) - if msg == "" { - msg = err.Error() - } + msg := "" - return fmt.Errorf(msg) + if err == nil { + msg = fmt.Sprintf("namespace '%s' still exists, after delete", namespace) + } - }, time.Now().Add(120*time.Second)); err != nil { - return err + if msg == "" && err != nil && strings.Contains(err.Error(), "not found") { + // Success is an error containing 'applicationset-e2e' not found. + return nil } - return nil + if msg == "" { + msg = err.Error() + } + + return fmt.Errorf(msg) } // waitForSuccess waits for the condition to return a non-error value. diff --git a/test/e2e/fixture/cluster/actions.go b/test/e2e/fixture/cluster/actions.go index 3f047e8f9b03e..0613c9a22cf15 100644 --- a/test/e2e/fixture/cluster/actions.go +++ b/test/e2e/fixture/cluster/actions.go @@ -45,10 +45,10 @@ func (a *Actions) Create(args ...string) *Actions { Cluster: &v1alpha1.Cluster{ Server: a.context.server, Name: a.context.name, - Config: v1alpha1.ClusterConfig{}, + Config: v1alpha1.ClusterConfig{BearerToken: a.context.bearerToken}, ConnectionState: v1alpha1.ConnectionState{}, ServerVersion: "", - Namespaces: nil, + Namespaces: a.context.namespaces, RefreshRequestedAt: nil, Info: v1alpha1.ClusterInfo{}, Shard: nil, diff --git a/test/e2e/fixture/cluster/context.go b/test/e2e/fixture/cluster/context.go index 236be6a3a3913..bd0102f891d71 100644 --- a/test/e2e/fixture/cluster/context.go +++ b/test/e2e/fixture/cluster/context.go @@ -12,12 +12,13 @@ import ( type Context struct { t *testing.T // seconds - timeout int - name string - project string - server string - upsert bool - namespaces []string + timeout int + name string + project string + server string + upsert bool + namespaces []string + bearerToken string } func Given(t *testing.T) *Context { @@ -67,6 +68,11 @@ func (c *Context) Project(project string) *Context { return c } +func (c *Context) BearerToken(bearerToken string) *Context { + c.bearerToken = bearerToken + return c +} + func (c *Context) Upsert(upsert bool) *Context { c.upsert = upsert return c diff --git a/test/e2e/fixture/fixture.go b/test/e2e/fixture/fixture.go index 0d758c8abbe74..f8dd60cb74974 100644 --- a/test/e2e/fixture/fixture.go +++ b/test/e2e/fixture/fixture.go @@ -15,7 +15,6 @@ import ( "github.com/argoproj/pkg/errors" jsonpatch "github.com/evanphx/json-patch" - "github.com/ghodss/yaml" log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -23,12 +22,14 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/pkg/apiclient" sessionpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/session" "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/util/env" . "github.com/argoproj/argo-cd/v2/util/errors" grpcutil "github.com/argoproj/argo-cd/v2/util/grpc" "github.com/argoproj/argo-cd/v2/util/io" @@ -57,28 +58,40 @@ const ( // cmp plugin sock file path PluginSockFilePath = "/app/config/plugin" + + E2ETestPrefix = "e2e-test-" ) const ( - EnvAdminUsername = "ARGOCD_E2E_ADMIN_USERNAME" - EnvAdminPassword = "ARGOCD_E2E_ADMIN_PASSWORD" + EnvAdminUsername = "ARGOCD_E2E_ADMIN_USERNAME" + EnvAdminPassword = "ARGOCD_E2E_ADMIN_PASSWORD" + EnvArgoCDServerName = "ARGOCD_E2E_SERVER_NAME" + EnvArgoCDRedisHAProxyName = "ARGOCD_E2E_REDIS_HAPROXY_NAME" + EnvArgoCDRedisName = "ARGOCD_E2E_REDIS_NAME" + EnvArgoCDRepoServerName = "ARGOCD_E2E_REPO_SERVER_NAME" + EnvArgoCDAppControllerName = "ARGOCD_E2E_APPLICATION_CONTROLLER_NAME" ) var ( - id string - deploymentNamespace string - name string - KubeClientset kubernetes.Interface - KubeConfig *rest.Config - DynamicClientset dynamic.Interface - AppClientset appclientset.Interface - ArgoCDClientset apiclient.Client - adminUsername string - AdminPassword string - apiServerAddress string - token string - plainText bool - testsRun map[string]bool + id string + deploymentNamespace string + name string + KubeClientset kubernetes.Interface + KubeConfig *rest.Config + DynamicClientset dynamic.Interface + AppClientset appclientset.Interface + ArgoCDClientset apiclient.Client + adminUsername string + AdminPassword string + apiServerAddress string + token string + plainText bool + testsRun map[string]bool + argoCDServerName string + argoCDRedisHAProxyName string + argoCDRedisName string + argoCDRepoServerName string + argoCDAppControllerName string ) type RepoURLType string @@ -92,6 +105,7 @@ type ACL struct { const ( RepoURLTypeFile = "file" RepoURLTypeHTTPS = "https" + RepoURLTypeHTTPSOrg = "https-org" RepoURLTypeHTTPSClientCert = "https-cc" RepoURLTypeHTTPSSubmodule = "https-sub" RepoURLTypeHTTPSSubmoduleParent = "https-par" @@ -103,6 +117,8 @@ const ( RepoURLTypeHelmOCI = "helm-oci" GitUsername = "admin" GitPassword = "password" + GithubAppID = "2978632978" + GithubAppInstallationID = "7893789433789" GpgGoodKeyID = "D56C4FCA57A46444" HelmOCIRegistryURL = "localhost:5000/myrepo" ) @@ -139,8 +155,7 @@ func GetEnvWithDefault(envName, defaultValue string) string { // IsRemote returns true when the tests are being run against a workload that // is running in a remote cluster. func IsRemote() bool { - r := os.Getenv("ARGOCD_E2E_REMOTE") - return r == "true" + return env.ParseBoolFromEnv("ARGOCD_E2E_REMOTE", false) } // IsLocal returns when the tests are being run against a local workload @@ -164,11 +179,26 @@ func init() { adminUsername = GetEnvWithDefault(EnvAdminUsername, defaultAdminUsername) AdminPassword = GetEnvWithDefault(EnvAdminPassword, defaultAdminPassword) + argoCDServerName = GetEnvWithDefault(EnvArgoCDServerName, common.DefaultServerName) + argoCDRedisHAProxyName = GetEnvWithDefault(EnvArgoCDRedisHAProxyName, common.DefaultRedisHaProxyName) + argoCDRedisName = GetEnvWithDefault(EnvArgoCDRedisName, common.DefaultRedisName) + argoCDRepoServerName = GetEnvWithDefault(EnvArgoCDRepoServerName, common.DefaultRepoServerName) + argoCDAppControllerName = GetEnvWithDefault(EnvArgoCDAppControllerName, common.DefaultApplicationControllerName) + dialTime := 30 * time.Second tlsTestResult, err := grpcutil.TestTLS(apiServerAddress, dialTime) CheckError(err) - ArgoCDClientset, err = apiclient.NewClient(&apiclient.ClientOptions{Insecure: true, ServerAddr: apiServerAddress, PlainText: !tlsTestResult.TLS}) + ArgoCDClientset, err = apiclient.NewClient(&apiclient.ClientOptions{ + Insecure: true, + ServerAddr: apiServerAddress, + PlainText: !tlsTestResult.TLS, + ServerName: argoCDServerName, + RedisHaProxyName: argoCDRedisHAProxyName, + RedisName: argoCDRedisName, + RepoServerName: argoCDRepoServerName, + AppControllerName: argoCDAppControllerName, + }) CheckError(err) plainText = !tlsTestResult.TLS @@ -214,10 +244,15 @@ func loginAs(username, password string) { token = sessionResponse.Token ArgoCDClientset, err = apiclient.NewClient(&apiclient.ClientOptions{ - Insecure: true, - ServerAddr: apiServerAddress, - AuthToken: token, - PlainText: plainText, + Insecure: true, + ServerAddr: apiServerAddress, + AuthToken: token, + PlainText: plainText, + ServerName: argoCDServerName, + RedisHaProxyName: argoCDRedisHAProxyName, + RedisName: argoCDRedisName, + RepoServerName: argoCDRepoServerName, + AppControllerName: argoCDAppControllerName, }) CheckError(err) } @@ -251,6 +286,7 @@ const ( EnvRepoURLTypeSSHSubmodule = "ARGOCD_E2E_REPO_SSH_SUBMODULE" EnvRepoURLTypeSSHSubmoduleParent = "ARGOCD_E2E_REPO_SSH_SUBMODULE_PARENT" EnvRepoURLTypeHTTPS = "ARGOCD_E2E_REPO_HTTPS" + EnvRepoURLTypeHTTPSOrg = "ARGOCD_E2E_REPO_HTTPS_ORG" EnvRepoURLTypeHTTPSClientCert = "ARGOCD_E2E_REPO_HTTPS_CLIENT_CERT" EnvRepoURLTypeHTTPSSubmodule = "ARGOCD_E2E_REPO_HTTPS_SUBMODULE" EnvRepoURLTypeHTTPSSubmoduleParent = "ARGOCD_E2E_REPO_HTTPS_SUBMODULE_PARENT" @@ -272,6 +308,9 @@ func RepoURL(urlType RepoURLType) string { // Git server via HTTPS case RepoURLTypeHTTPS: return GetEnvWithDefault(EnvRepoURLTypeHTTPS, "https://localhost:9443/argo-e2e/testdata.git") + // Git "organisation" via HTTPS + case RepoURLTypeHTTPSOrg: + return GetEnvWithDefault(EnvRepoURLTypeHTTPSOrg, "https://localhost:9443/argo-e2e") // Git server via HTTPS - Client Cert protected case RepoURLTypeHTTPSClientCert: return GetEnvWithDefault(EnvRepoURLTypeHTTPSClientCert, "https://localhost:9444/argo-e2e/testdata.git") @@ -443,17 +482,6 @@ func SetPermissions(permissions []ACL, username string, roleName string) { }) } -func SetConfigManagementPlugins(plugin ...v1alpha1.ConfigManagementPlugin) { - updateSettingConfigMap(func(cm *corev1.ConfigMap) error { - yamlBytes, err := yaml.Marshal(plugin) - if err != nil { - return err - } - cm.Data["configManagementPlugins"] = string(yamlBytes) - return nil - }) -} - func SetResourceFilter(filters settings.ResourcesFilter) { updateSettingConfigMap(func(cm *corev1.ConfigMap) error { exclusions, err := yaml.Marshal(filters.ResourceExclusions) @@ -514,7 +542,30 @@ func SetParamInNotificationsConfigMap(key, value string) { }) } -func EnsureCleanState(t *testing.T) { +type TestOption func(option *testOption) + +type testOption struct { + testdata string +} + +func newTestOption(opts ...TestOption) *testOption { + to := &testOption{ + testdata: "testdata", + } + for _, opt := range opts { + opt(to) + } + return to +} + +func WithTestData(testdata string) TestOption { + return func(option *testOption) { + option.testdata = testdata + } +} + +func EnsureCleanState(t *testing.T, opts ...TestOption) { + opt := newTestOption(opts...) // In large scenarios, we can skip tests that already run SkipIfAlreadyRun(t) // Register this test after it has been run & was successfull @@ -632,9 +683,9 @@ func EnsureCleanState(t *testing.T) { } // set-up tmp repo, must have unique name - FailOnErr(Run("", "cp", "-Rf", "testdata", repoDirectory())) + FailOnErr(Run("", "cp", "-Rf", opt.testdata, repoDirectory())) FailOnErr(Run(repoDirectory(), "chmod", "777", ".")) - FailOnErr(Run(repoDirectory(), "git", "init")) + FailOnErr(Run(repoDirectory(), "git", "init", "-b", "master")) FailOnErr(Run(repoDirectory(), "git", "add", ".")) FailOnErr(Run(repoDirectory(), "git", "commit", "-q", "-m", "initial commit")) @@ -647,9 +698,49 @@ func EnsureCleanState(t *testing.T) { FailOnErr(Run("", "kubectl", "create", "ns", DeploymentNamespace())) FailOnErr(Run("", "kubectl", "label", "ns", DeploymentNamespace(), TestingLabel+"=true")) + // delete old namespaces used by E2E tests + namespaces, err := KubeClientset.CoreV1().Namespaces().List(context.Background(), v1.ListOptions{}) + CheckError(err) + for _, namespace := range namespaces.Items { + if strings.HasPrefix(namespace.Name, E2ETestPrefix) { + FailOnErr(Run("", "kubectl", "delete", "ns", namespace.Name)) + } + } + + // delete old ClusterRoles that begin with "e2e-test-" prefix (E2ETestPrefix), which were created by tests + clusterRoles, err := KubeClientset.RbacV1().ClusterRoles().List(context.Background(), v1.ListOptions{}) + CheckError(err) + for _, clusterRole := range clusterRoles.Items { + if strings.HasPrefix(clusterRole.Name, E2ETestPrefix) { + FailOnErr(Run("", "kubectl", "delete", "clusterrole", clusterRole.Name)) + } + } + + // delete old ClusterRoleBindings that begin with "e2e-test-prefix", which were created by E2E tests + clusterRoleBindings, err := KubeClientset.RbacV1().ClusterRoleBindings().List(context.Background(), v1.ListOptions{}) + CheckError(err) + for _, clusterRoleBinding := range clusterRoleBindings.Items { + if strings.HasPrefix(clusterRoleBinding.Name, E2ETestPrefix) { + FailOnErr(Run("", "kubectl", "delete", "clusterrolebinding", clusterRoleBinding.Name)) + } + } + log.WithFields(log.Fields{"duration": time.Since(start), "name": t.Name(), "id": id, "username": "admin", "password": "password"}).Info("clean state") } +func RunCliWithRetry(maxRetries int, args ...string) (string, error) { + var out string + var err error + for i := 0; i < maxRetries; i++ { + out, err = RunCli(args...) + if err == nil { + break + } + time.Sleep(time.Second) + } + return out, err +} + func RunCli(args ...string) (string, error) { return RunCliWithStdin("", args...) } @@ -747,6 +838,26 @@ func AddSignedFile(path, contents string) { } } +func AddSignedTag(name string) { + prevGnuPGHome := os.Getenv("GNUPGHOME") + os.Setenv("GNUPGHOME", TmpDir+"/gpg") + defer os.Setenv("GNUPGHOME", prevGnuPGHome) + FailOnErr(Run(repoDirectory(), "git", "-c", fmt.Sprintf("user.signingkey=%s", GpgGoodKeyID), "tag", "-sm", "add signed tag", name)) + if IsRemote() { + FailOnErr(Run(repoDirectory(), "git", "push", "--tags", "-f", "origin", "master")) + } +} + +func AddTag(name string) { + prevGnuPGHome := os.Getenv("GNUPGHOME") + os.Setenv("GNUPGHOME", TmpDir+"/gpg") + defer os.Setenv("GNUPGHOME", prevGnuPGHome) + FailOnErr(Run(repoDirectory(), "git", "tag", name)) + if IsRemote() { + FailOnErr(Run(repoDirectory(), "git", "push", "--tags", "-f", "origin", "master")) + } +} + // create the resource by creating using "kubectl apply", with bonus templating func Declarative(filename string, values interface{}) (string, error) { @@ -762,13 +873,10 @@ func Declarative(filename string, values interface{}) (string, error) { } func CreateSubmoduleRepos(repoType string) { - oldEnv := os.Getenv("GIT_ALLOW_PROTOCOL") - CheckError(os.Setenv("GIT_ALLOW_PROTOCOL", "file")) - // set-up submodule repo FailOnErr(Run("", "cp", "-Rf", "testdata/git-submodule/", submoduleDirectory())) FailOnErr(Run(submoduleDirectory(), "chmod", "777", ".")) - FailOnErr(Run(submoduleDirectory(), "git", "init")) + FailOnErr(Run(submoduleDirectory(), "git", "init", "-b", "master")) FailOnErr(Run(submoduleDirectory(), "git", "add", ".")) FailOnErr(Run(submoduleDirectory(), "git", "commit", "-q", "-m", "initial commit")) @@ -780,9 +888,20 @@ func CreateSubmoduleRepos(repoType string) { // set-up submodule parent repo FailOnErr(Run("", "mkdir", submoduleParentDirectory())) FailOnErr(Run(submoduleParentDirectory(), "chmod", "777", ".")) - FailOnErr(Run(submoduleParentDirectory(), "git", "init")) + FailOnErr(Run(submoduleParentDirectory(), "git", "init", "-b", "master")) FailOnErr(Run(submoduleParentDirectory(), "git", "add", ".")) - FailOnErr(Run(submoduleParentDirectory(), "git", "submodule", "add", "-b", "master", "../submodule.git", "submodule/test")) + if IsRemote() { + FailOnErr(Run(submoduleParentDirectory(), "git", "submodule", "add", "-b", "master", os.Getenv("ARGOCD_E2E_GIT_SERVICE_SUBMODULE"), "submodule/test")) + } else { + oldAllowProtocol, isAllowProtocolSet := os.LookupEnv("GIT_ALLOW_PROTOCOL") + CheckError(os.Setenv("GIT_ALLOW_PROTOCOL", "file")) + FailOnErr(Run(submoduleParentDirectory(), "git", "submodule", "add", "-b", "master", "../submodule.git", "submodule/test")) + if isAllowProtocolSet { + CheckError(os.Setenv("GIT_ALLOW_PROTOCOL", oldAllowProtocol)) + } else { + CheckError(os.Unsetenv("GIT_ALLOW_PROTOCOL")) + } + } if repoType == "ssh" { FailOnErr(Run(submoduleParentDirectory(), "git", "config", "--file=.gitmodules", "submodule.submodule/test.url", RepoURL(RepoURLTypeSSHSubmodule))) } else if repoType == "https" { @@ -795,8 +914,18 @@ func CreateSubmoduleRepos(repoType string) { FailOnErr(Run(submoduleParentDirectory(), "git", "remote", "add", "origin", os.Getenv("ARGOCD_E2E_GIT_SERVICE_SUBMODULE_PARENT"))) FailOnErr(Run(submoduleParentDirectory(), "git", "push", "origin", "master", "-f")) } +} - CheckError(os.Setenv("GIT_ALLOW_PROTOCOL", oldEnv)) +func RemoveSubmodule() { + log.Info("removing submodule") + + FailOnErr(Run(submoduleParentDirectory(), "git", "rm", "submodule/test")) + FailOnErr(Run(submoduleParentDirectory(), "touch", "submodule/.gitkeep")) + FailOnErr(Run(submoduleParentDirectory(), "git", "add", "submodule/.gitkeep")) + FailOnErr(Run(submoduleParentDirectory(), "git", "commit", "-m", "remove submodule")) + if IsRemote() { + FailOnErr(Run(submoduleParentDirectory(), "git", "push", "-f", "origin", "master")) + } } // RestartRepoServer performs a restart of the repo server deployment and waits @@ -809,8 +938,10 @@ 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) } } @@ -824,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 58c56046d3858..00c123ab5d893 100644 --- a/test/e2e/fixture/http.go +++ b/test/e2e/fixture/http.go @@ -2,6 +2,7 @@ package fixture import ( "bytes" + "crypto/tls" "encoding/json" "io" "net/http" @@ -27,7 +28,15 @@ func DoHttpRequest(method string, path string, data ...byte) (*http.Response, er return nil, err } req.AddCookie(&http.Cookie{Name: common.AuthCookieName, Value: token}) - return http.DefaultClient.Do(req) + req.Header.Set("Content-Type", "application/json") + + httpClient := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: IsRemote()}, + }, + } + + return httpClient.Do(req) } // DoHttpJsonRequest executes a http request against the Argo CD API server and unmarshals the response body as JSON diff --git a/test/e2e/fixture/project/actions.go b/test/e2e/fixture/project/actions.go index 81943c4fc2b6c..61a2ad90615fb 100644 --- a/test/e2e/fixture/project/actions.go +++ b/test/e2e/fixture/project/actions.go @@ -52,10 +52,10 @@ func (a *Actions) AddSource(repo string) *Actions { } func (a *Actions) UpdateProject(updater func(project *v1alpha1.AppProject)) *Actions { - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.TODO(), a.context.name, v1.GetOptions{}) + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.TODO(), a.context.name, v1.GetOptions{}) require.NoError(a.context.t, err) updater(proj) - _, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Update(context.TODO(), proj, v1.UpdateOptions{}) + _, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Update(context.TODO(), proj, v1.UpdateOptions{}) require.NoError(a.context.t, err) return a } diff --git a/test/e2e/git_submodule_test.go b/test/e2e/git_submodule_test.go index 27476db84a1ed..525c13d4b35ef 100644 --- a/test/e2e/git_submodule_test.go +++ b/test/e2e/git_submodule_test.go @@ -40,3 +40,25 @@ func TestGitSubmoduleHTTPSSupport(t *testing.T) { Expect(SyncStatusIs(SyncStatusCodeSynced)). Expect(Pod(func(p v1.Pod) bool { return p.Name == "pod-in-submodule" })) } + +func TestGitSubmoduleRemovalSupport(t *testing.T) { + Given(t). + RepoURLType(fixture.RepoURLTypeSSHSubmoduleParent). + Path("submodule"). + Recurse(). + CustomSSHKnownHostsAdded(). + SubmoduleSSHRepoURLAdded(true). + When(). + CreateFromFile(func(app *Application) {}). + Sync(). + Then(). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(Pod(func(p v1.Pod) bool { return p.Name == "pod-in-submodule" })). + When(). + RemoveSubmodule(). + Refresh(RefreshTypeNormal). + Sync(). + Then(). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(NotPod(func(p v1.Pod) bool { return p.Name == "pod-in-submodule" })) +} diff --git a/test/e2e/helm_test.go b/test/e2e/helm_test.go index 318fad17d97eb..5fd774ea0c46d 100644 --- a/test/e2e/helm_test.go +++ b/test/e2e/helm_test.go @@ -6,6 +6,7 @@ import ( "net" "net/http" "os" + "strings" "testing" "github.com/argoproj/gitops-engine/pkg/health" @@ -19,6 +20,7 @@ import ( "github.com/argoproj/argo-cd/v2/test/e2e/fixture" . "github.com/argoproj/argo-cd/v2/test/e2e/fixture" . "github.com/argoproj/argo-cd/v2/test/e2e/fixture/app" + projectFixture "github.com/argoproj/argo-cd/v2/test/e2e/fixture/project" "github.com/argoproj/argo-cd/v2/test/e2e/fixture/repos" . "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/settings" @@ -200,7 +202,7 @@ func TestHelmValuesLiteralFileLocal(t *testing.T) { if err != nil { panic(err) } - assert.Equal(t, string(data), app.Spec.GetSource().Helm.Values) + assert.Equal(t, strings.TrimSuffix(string(data), "\n"), app.Spec.GetSource().Helm.ValuesString()) }). When(). AppUnSet("--values-literal"). @@ -242,7 +244,7 @@ func TestHelmValuesLiteralFileRemote(t *testing.T) { AppSet("--values-literal-file", "http://"+address). Then(). And(func(app *Application) { - assert.Equal(t, "a: b", app.Spec.GetSource().Helm.Values) + assert.Equal(t, "a: b", app.Spec.GetSource().Helm.ValuesString()) }). When(). AppUnSet("--values-literal"). @@ -399,6 +401,45 @@ func TestHelmWithMultipleDependencies(t *testing.T) { Expect(SyncStatusIs(SyncStatusCodeSynced)) } +func TestHelmDependenciesPermissionDenied(t *testing.T) { + SkipOnEnv(t, "HELM") + + projName := "argo-helm-project-denied" + projectFixture. + Given(t). + Name(projName). + Destination("*,*"). + When(). + Create(). + AddSource(RepoURL(RepoURLTypeFile)) + + expectedErr := fmt.Sprintf("helm repos localhost:5000/myrepo are not permitted in project '%s'", projName) + GivenWithSameState(t). + Project(projName). + Path("helm-oci-with-dependencies"). + CustomCACertAdded(). + HelmHTTPSCredentialsUserPassAdded(). + HelmPassCredentials(). + When(). + IgnoreErrors(). + CreateApp(). + Then(). + Expect(Error("", expectedErr)) + + expectedErr = fmt.Sprintf("helm repos https://localhost:9443/argo-e2e/testdata.git/helm-repo/local, https://localhost:9443/argo-e2e/testdata.git/helm-repo/local2 are not permitted in project '%s'", projName) + GivenWithSameState(t). + Project(projName). + Path("helm-with-multiple-dependencies-permission-denied"). + CustomCACertAdded(). + HelmHTTPSCredentialsUserPassAdded(). + HelmPassCredentials(). + When(). + IgnoreErrors(). + CreateApp(). + Then(). + Expect(Error("", expectedErr)) +} + func TestHelmWithDependenciesLegacyRepo(t *testing.T) { SkipOnEnv(t, "HELM") testHelmWithDependencies(t, "helm-with-dependencies", true) @@ -413,13 +454,13 @@ func testHelmWithDependencies(t *testing.T, chartPath string, legacyRepo bool) { if legacyRepo { ctx.And(func() { FailOnErr(fixture.Run("", "kubectl", "create", "secret", "generic", "helm-repo", - "-n", fixture.ArgoCDNamespace, + "-n", fixture.TestNamespace(), fmt.Sprintf("--from-file=certSecret=%s", repos.CertPath), fmt.Sprintf("--from-file=keySecret=%s", repos.CertKeyPath), fmt.Sprintf("--from-literal=username=%s", GitUsername), fmt.Sprintf("--from-literal=password=%s", GitPassword), )) - FailOnErr(fixture.KubeClientset.CoreV1().Secrets(fixture.ArgoCDNamespace).Patch(context.Background(), + FailOnErr(fixture.KubeClientset.CoreV1().Secrets(fixture.TestNamespace()).Patch(context.Background(), "helm-repo", types.MergePatchType, []byte(`{"metadata": { "labels": {"e2e.argoproj.io": "true"} }}`), metav1.PatchOptions{})) fixture.SetHelmRepos(settings.HelmRepoCredentials{ 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/jsonnet_test.go b/test/e2e/jsonnet_test.go index 7cc50d2bccab5..cad88f34a0048 100644 --- a/test/e2e/jsonnet_test.go +++ b/test/e2e/jsonnet_test.go @@ -102,7 +102,7 @@ func TestJsonnetExtVarEnv(t *testing.T) { }) } -//Jsonnet file located in nested sub directory uses import +// Jsonnet file located in nested sub directory uses import func TestJsonnetNestedDirWithImports(t *testing.T) { Given(t). Path("jsonnet-nested-dir-with-imports/apps"). diff --git a/test/e2e/kustomize_test.go b/test/e2e/kustomize_test.go index e6840e7b95eba..862e55c9e9502 100644 --- a/test/e2e/kustomize_test.go +++ b/test/e2e/kustomize_test.go @@ -1,6 +1,7 @@ package e2e import ( + "strconv" "testing" "github.com/argoproj/gitops-engine/pkg/health" @@ -146,7 +147,7 @@ func TestKustomizeBuildOptionsLoadRestrictor(t *testing.T) { Path(guestbookPath). And(func() { errors.FailOnErr(fixture.Run("", "kubectl", "patch", "cm", "argocd-cm", - "-n", fixture.ArgoCDNamespace, + "-n", fixture.TestNamespace(), "-p", `{ "data": { "kustomize.buildOptions": "--load-restrictor LoadRestrictionsNone" } }`)) }). When(). @@ -160,7 +161,7 @@ func TestKustomizeBuildOptionsLoadRestrictor(t *testing.T) { Given(). And(func() { errors.FailOnErr(fixture.Run("", "kubectl", "patch", "cm", "argocd-cm", - "-n", fixture.ArgoCDNamespace, + "-n", fixture.TestNamespace(), "-p", `{ "data": { "kustomize.buildOptions": "" } }`)) }) } @@ -179,6 +180,45 @@ func TestKustomizeImages(t *testing.T) { }) } +// make sure we we can invoke the CLI to replace replicas and actual deployment is set to correct value +func TestKustomizeReplicas2AppSource(t *testing.T) { + deploymentName := "guestbook-ui" + deploymentReplicas := 2 + checkReplicasFor := func(kind string) func(app *Application) { + return func(app *Application) { + name := deploymentName + replicas, err := fixture.Run( + "", "kubectl", "-n="+fixture.DeploymentNamespace(), + "get", kind, name, + "-ojsonpath={.spec.replicas}") + assert.NoError(t, err) + assert.Equal(t, strconv.Itoa(deploymentReplicas), replicas, "wrong value of replicas %s %s", kind, name) + } + } + + Given(t). + Path("guestbook"). + When(). + CreateApp(). + AppSet("--kustomize-replica", deploymentName+"=2"). + Then(). + And(func(app *Application) { + assert.Equal(t, deploymentName, app.Spec.Source.Kustomize.Replicas[0].Name) + }). + And(func(app *Application) { + assert.Equal(t, deploymentReplicas, int(app.Spec.Source.Kustomize.Replicas[0].Count.IntVal)) + }). // check Kustomize CLI + Expect(Success("")). + When(). + Sync(). + Then(). + Expect(Success("")). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(HealthIs(health.HealthStatusHealthy)). + And(checkReplicasFor("Deployment")) +} + // make sure we we can invoke the CLI to set namesuffix func TestKustomizeNameSuffix(t *testing.T) { Given(t). @@ -223,3 +263,27 @@ func TestKustomizeUnsetOverride(t *testing.T) { assert.Nil(t, app.Spec.GetSource().Kustomize) }) } + +// make sure we we can invoke the CLI to set and unset Deployment +func TestKustomizeUnsetOverrideDeployment(t *testing.T) { + deploymentName := "guestbook-ui" + deploymentReplicas := int32(2) + Given(t). + Path("guestbook"). + When(). // Replicas + CreateApp(). + AppSet("--kustomize-replica", deploymentName+"=2"). + Then(). + And(func(app *Application) { + assert.Equal(t, deploymentName, app.Spec.Source.Kustomize.Replicas[0].Name) + }). + And(func(app *Application) { + assert.Equal(t, deploymentReplicas, app.Spec.Source.Kustomize.Replicas[0].Count.IntVal) + }). + When(). + AppUnSet("--kustomize-replica", deploymentName). + Then(). + And(func(app *Application) { + assert.Nil(t, app.Spec.Source.Kustomize) + }) +} diff --git a/test/e2e/matrix_e2e_test.go b/test/e2e/matrix_e2e_test.go index f6b923f24b7a4..9fc023ecaaf69 100644 --- a/test/e2e/matrix_e2e_test.go +++ b/test/e2e/matrix_e2e_test.go @@ -11,18 +11,20 @@ import ( argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" . "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets" "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets/utils" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application" ) func TestListMatrixGenerator(t *testing.T) { generateExpectedApp := func(cluster, name string) argov1alpha1.Application { return argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-%s", cluster, name), - Namespace: utils.ArgoCDNamespace, + Namespace: utils.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -141,12 +143,12 @@ func TestClusterMatrixGenerator(t *testing.T) { generateExpectedApp := func(cluster, name string) argov1alpha1.Application { return argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-%s", cluster, name), - Namespace: utils.ArgoCDNamespace, + Namespace: utils.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -263,3 +265,304 @@ func TestClusterMatrixGenerator(t *testing.T) { When(). Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace)) } + +func TestMatrixTerminalMatrixGeneratorSelector(t *testing.T) { + generateExpectedApp := func(cluster, name string) argov1alpha1.Application { + return argov1alpha1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s", cluster, name), + Namespace: utils.TestNamespace(), + 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: name, + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: name, + }, + }, + } + } + + expectedApps1 := []argov1alpha1.Application{ + generateExpectedApp("cluster1", "kustomize-guestbook"), + generateExpectedApp("cluster1", "helm-guestbook"), + generateExpectedApp("cluster1", "ksonnet-guestbook"), + } + expectedApps2 := []argov1alpha1.Application{ + generateExpectedApp("cluster2", "kustomize-guestbook"), + generateExpectedApp("cluster2", "helm-guestbook"), + generateExpectedApp("cluster2", "ksonnet-guestbook"), + } + + Given(t). + // Create ApplicationSet with LabelSelector on an ApplicationSetTerminalGenerator + When(). + Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "matrix-generator-nested-matrix", + }, + Spec: v1alpha1.ApplicationSetSpec{ + ApplyNestedSelectors: true, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{values.name}}-{{path.basename}}"}, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "{{path}}", + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "{{path.basename}}", + }, + }, + }, + Generators: []v1alpha1.ApplicationSetGenerator{ + { + Matrix: &v1alpha1.MatrixGenerator{ + Generators: []v1alpha1.ApplicationSetNestedGenerator{ + { + Matrix: toAPIExtensionsJSON(t, &v1alpha1.NestedMatrixGenerator{ + Generators: []v1alpha1.ApplicationSetTerminalGenerator{ + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{ + {Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc", "values": {"name": "cluster1"}}`)}, + {Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc", "values": {"name": "cluster2"}}`)}, + }, + }, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "values.name": "cluster1", + }, + }, + }, + { + Git: &v1alpha1.GitGenerator{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + Directories: []v1alpha1.GitDirectoryGeneratorItem{ + { + Path: "*guestbook*", + }, + }, + }, + }, + }, + }), + }, + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{ + {Raw: []byte(`{}`)}, + }, + }, + }, + }, + }, + }, + }, + }, + }).Then().Expect(ApplicationsExist(expectedApps1)).Expect(ApplicationsDoNotExist(expectedApps2)). + + // Update the ApplicationSetTerminalGenerator LabelSelector, and verify the Applications are deleted and created + When(). + Update(func(appset *v1alpha1.ApplicationSet) { + appset.Spec.Generators[0].Matrix.Generators[0].Matrix = toAPIExtensionsJSON(t, &v1alpha1.NestedMatrixGenerator{ + Generators: []v1alpha1.ApplicationSetTerminalGenerator{ + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{ + {Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc", "values": {"name": "cluster1"}}`)}, + {Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc", "values": {"name": "cluster2"}}`)}, + }, + }, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "values.name": "cluster2", + }, + }, + }, + { + Git: &v1alpha1.GitGenerator{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + Directories: []v1alpha1.GitDirectoryGeneratorItem{ + { + Path: "*guestbook*", + }, + }, + }, + }, + }, + }) + }).Then().Expect(ApplicationsExist(expectedApps2)).Expect(ApplicationsDoNotExist(expectedApps1)). + + // Set ApplyNestedSelector to false and verify all Applications are created + When(). + Update(func(appset *v1alpha1.ApplicationSet) { + appset.Spec.ApplyNestedSelectors = false + }).Then().Expect(ApplicationsExist(expectedApps1)).Expect(ApplicationsExist(expectedApps2)). + + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist(expectedApps1)).Expect(ApplicationsDoNotExist(expectedApps2)) +} + +func TestMatrixTerminalMergeGeneratorSelector(t *testing.T) { + generateExpectedApp := func(name, nameSuffix string) argov1alpha1.Application { + return argov1alpha1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s", name, nameSuffix), + Namespace: utils.TestNamespace(), + 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: name, + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: name, + }, + }, + } + } + + expectedApps1 := []argov1alpha1.Application{ + generateExpectedApp("kustomize-guestbook", "1"), + } + expectedApps2 := []argov1alpha1.Application{ + generateExpectedApp("helm-guestbook", "2"), + } + + Given(t). + // Create ApplicationSet with LabelSelector on an ApplicationSetTerminalGenerator + When(). + Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "matrix-generator-nested-merge", + }, + Spec: v1alpha1.ApplicationSetSpec{ + ApplyNestedSelectors: true, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{path.basename}}-{{name-suffix}}"}, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "{{path}}", + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "{{path.basename}}", + }, + }, + }, + Generators: []v1alpha1.ApplicationSetGenerator{ + { + Matrix: &v1alpha1.MatrixGenerator{ + Generators: []v1alpha1.ApplicationSetNestedGenerator{ + { + Merge: toAPIExtensionsJSON(t, &v1alpha1.NestedMergeGenerator{ + MergeKeys: []string{"path.basename"}, + Generators: []v1alpha1.ApplicationSetTerminalGenerator{ + { + Git: &v1alpha1.GitGenerator{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + Directories: []v1alpha1.GitDirectoryGeneratorItem{ + { + Path: "*guestbook*", + }, + }, + }, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "path.basename": "kustomize-guestbook", + }, + }, + }, + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{ + {Raw: []byte(`{"path.basename": "kustomize-guestbook", "name-suffix": "1"}`)}, + {Raw: []byte(`{"path.basename": "helm-guestbook", "name-suffix": "2"}`)}, + }, + }, + }, + }, + }), + }, + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{ + {Raw: []byte(`{}`)}, + }, + }, + }, + }, + }, + }, + }, + }, + }).Then().Expect(ApplicationsExist(expectedApps1)).Expect(ApplicationsDoNotExist(expectedApps2)). + + // Update the ApplicationSetTerminalGenerator LabelSelector, and verify the Applications are deleted and created + When(). + Update(func(appset *v1alpha1.ApplicationSet) { + + appset.Spec.Generators[0].Matrix.Generators[0].Merge = toAPIExtensionsJSON(t, &v1alpha1.NestedMergeGenerator{ + MergeKeys: []string{"path.basename"}, + Generators: []v1alpha1.ApplicationSetTerminalGenerator{ + { + Git: &v1alpha1.GitGenerator{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + Directories: []v1alpha1.GitDirectoryGeneratorItem{ + { + Path: "*guestbook*", + }, + }, + }, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "path.basename": "helm-guestbook", + }, + }, + }, + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{ + {Raw: []byte(`{"path.basename": "kustomize-guestbook", "name-suffix": "1"}`)}, + {Raw: []byte(`{"path.basename": "helm-guestbook", "name-suffix": "2"}`)}, + }, + }, + }, + }, + }) + }).Then().Expect(ApplicationsExist(expectedApps2)).Expect(ApplicationsDoNotExist(expectedApps1)). + + // Set ApplyNestedSelector to false and verify all Applications are created + When(). + Update(func(appset *v1alpha1.ApplicationSet) { + appset.Spec.ApplyNestedSelectors = false + }).Then().Expect(ApplicationsExist(expectedApps1)).Expect(ApplicationsExist(expectedApps2)). + + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist(expectedApps1)).Expect(ApplicationsDoNotExist(expectedApps2)) +} diff --git a/test/e2e/merge_e2e_test.go b/test/e2e/merge_e2e_test.go index 6a3de30f19f84..9ad148b65b985 100644 --- a/test/e2e/merge_e2e_test.go +++ b/test/e2e/merge_e2e_test.go @@ -12,18 +12,20 @@ import ( argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" . "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets" "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets/utils" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application" ) func TestListMergeGenerator(t *testing.T) { generateExpectedApp := func(name, nameSuffix string) argov1alpha1.Application { return argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-%s", name, nameSuffix), - Namespace: utils.ArgoCDNamespace, + Namespace: utils.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -138,12 +140,12 @@ func TestClusterMergeGenerator(t *testing.T) { generateExpectedApp := func(cluster, name, nameSuffix string) argov1alpha1.Application { return argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ - Kind: "Application", + Kind: application.ApplicationKind, APIVersion: "argoproj.io/v1alpha1", }, ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-%s-%s", cluster, name, nameSuffix), - Namespace: utils.ArgoCDNamespace, + Namespace: utils.TestNamespace(), Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -279,6 +281,157 @@ func TestClusterMergeGenerator(t *testing.T) { Delete().Then().Expect(ApplicationsDoNotExist(expectedAppsNewNamespace)) } +func TestMergeTerminalMergeGeneratorSelector(t *testing.T) { + generateExpectedApp := func(name, nameSuffix string) argov1alpha1.Application { + return argov1alpha1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s", name, nameSuffix), + Namespace: utils.TestNamespace(), + 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: name, + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: name, + }, + }, + } + } + + expectedApps1 := []argov1alpha1.Application{ + generateExpectedApp("kustomize-guestbook", "1"), + } + expectedApps2 := []argov1alpha1.Application{ + generateExpectedApp("helm-guestbook", "2"), + } + + Given(t). + // Create ApplicationSet with LabelSelector on an ApplicationSetTerminalGenerator + When(). + Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "merge-generator-nested-merge", + }, + Spec: v1alpha1.ApplicationSetSpec{ + ApplyNestedSelectors: true, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{path.basename}}-{{name-suffix}}"}, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "{{path}}", + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "{{path.basename}}", + }, + }, + }, + Generators: []v1alpha1.ApplicationSetGenerator{ + { + Merge: &v1alpha1.MergeGenerator{ + MergeKeys: []string{"path.basename"}, + Generators: []v1alpha1.ApplicationSetNestedGenerator{ + { + Merge: toAPIExtensionsJSON(t, &v1alpha1.NestedMergeGenerator{ + MergeKeys: []string{"path.basename"}, + Generators: []v1alpha1.ApplicationSetTerminalGenerator{ + { + Git: &v1alpha1.GitGenerator{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + Directories: []v1alpha1.GitDirectoryGeneratorItem{ + { + Path: "*guestbook*", + }, + }, + }, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "path.basename": "kustomize-guestbook", + }, + }, + }, + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{ + {Raw: []byte(`{"path.basename": "kustomize-guestbook", "name-suffix": "1"}`)}, + {Raw: []byte(`{"path.basename": "helm-guestbook", "name-suffix": "2"}`)}, + }, + }, + }, + }, + }), + }, + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{ + {Raw: []byte(`{}`)}, + }, + }, + }, + }, + }, + }, + }, + }, + }).Then().Expect(ApplicationsExist(expectedApps1)).Expect(ApplicationsDoNotExist(expectedApps2)). + + // Update the ApplicationSetTerminalGenerator LabelSelector, and verify the Applications are deleted and created + When(). + Update(func(appset *v1alpha1.ApplicationSet) { + + appset.Spec.Generators[0].Merge.Generators[0].Merge = toAPIExtensionsJSON(t, &v1alpha1.NestedMergeGenerator{ + MergeKeys: []string{"path.basename"}, + Generators: []v1alpha1.ApplicationSetTerminalGenerator{ + { + Git: &v1alpha1.GitGenerator{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + Directories: []v1alpha1.GitDirectoryGeneratorItem{ + { + Path: "*guestbook*", + }, + }, + }, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "path.basename": "helm-guestbook", + }, + }, + }, + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{ + {Raw: []byte(`{"path.basename": "kustomize-guestbook", "name-suffix": "1"}`)}, + {Raw: []byte(`{"path.basename": "helm-guestbook", "name-suffix": "2"}`)}, + }, + }, + }, + }, + }) + }).Then().Expect(ApplicationsExist(expectedApps2)).Expect(ApplicationsDoNotExist(expectedApps1)). + + // Set ApplyNestedSelector to false and verify all Applications are created + When(). + Update(func(appset *v1alpha1.ApplicationSet) { + appset.Spec.ApplyNestedSelectors = false + }).Then().Expect(ApplicationsExist(expectedApps1)).Expect(ApplicationsExist(expectedApps2)). + + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist(expectedApps1)).Expect(ApplicationsDoNotExist(expectedApps2)) +} + func toAPIExtensionsJSON(t *testing.T, g interface{}) *apiextensionsv1.JSON { resVal, err := json.Marshal(g) diff --git a/test/e2e/multiarch-container/Dockerfile b/test/e2e/multiarch-container/Dockerfile index 41667d28f8176..8fd87a833defb 100644 --- a/test/e2e/multiarch-container/Dockerfile +++ b/test/e2e/multiarch-container/Dockerfile @@ -1,2 +1,2 @@ -FROM docker.io/library/busybox +FROM docker.io/library/busybox@sha256:650fd573e056b679a5110a70aabeb01e26b76e545ec4b9c70a9523f2dfaf18c6 CMD exec sh -c "trap : TERM INT; echo 'Hi' && tail -f /dev/null" diff --git a/test/e2e/notification_test.go b/test/e2e/notification_test.go index ce18f793a9afa..eebe4d8991ae5 100644 --- a/test/e2e/notification_test.go +++ b/test/e2e/notification_test.go @@ -12,10 +12,10 @@ 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{¬ification.Service{Name: pointer.String("test")}}, services.Items) + assert.Equal(t, []*notification.Service{{Name: pointer.String("test")}}, services.Items) }) } @@ -25,7 +25,7 @@ func TestNotificationsListTemplates(t *testing.T) { SetParamInNotificationConfigMap("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"). Then().Templates(func(templates *notification.TemplateList, err error) { assert.Nil(t, err) - assert.Equal(t, []*notification.Template{¬ification.Template{Name: pointer.String("app-created")}}, templates.Items) + assert.Equal(t, []*notification.Template{{Name: pointer.String("app-created")}}, templates.Items) }) } @@ -35,6 +35,6 @@ func TestNotificationsListTriggers(t *testing.T) { SetParamInNotificationConfigMap("trigger.on-created", "- description: Application is created.\n oncePer: app.metadata.name\n send:\n - app-created\n when: \"true\"\n"). Then().Triggers(func(triggers *notification.TriggerList, err error) { assert.Nil(t, err) - assert.Equal(t, []*notification.Trigger{¬ification.Trigger{Name: pointer.String("on-created")}}, triggers.Items) + assert.Equal(t, []*notification.Trigger{{Name: pointer.String("on-created")}}, triggers.Items) }) } diff --git a/test/e2e/project_management_test.go b/test/e2e/project_management_test.go index 4cfe088ef5de4..fb8886a21dbd4 100644 --- a/test/e2e/project_management_test.go +++ b/test/e2e/project_management_test.go @@ -21,11 +21,11 @@ import ( ) func assertProjHasEvent(t *testing.T, a *v1alpha1.AppProject, message string, reason string) { - list, err := fixture.KubeClientset.CoreV1().Events(fixture.ArgoCDNamespace).List(context.Background(), metav1.ListOptions{ + list, err := fixture.KubeClientset.CoreV1().Events(fixture.TestNamespace()).List(context.Background(), metav1.ListOptions{ FieldSelector: fields.SelectorFromSet(map[string]string{ "involvedObject.name": a.Name, "involvedObject.uid": string(a.UID), - "involvedObject.namespace": fixture.ArgoCDNamespace, + "involvedObject.namespace": fixture.TestNamespace(), }).String(), }) assert.NoError(t, err) @@ -51,7 +51,7 @@ func TestProjectCreation(t *testing.T) { "--orphaned-resources") assert.Nil(t, err) - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.NoError(t, err) assert.Equal(t, projectName, proj.Name) assert.Equal(t, 2, len(proj.Spec.Destinations)) @@ -87,7 +87,7 @@ func TestProjectCreation(t *testing.T) { _, err = fixture.RunCliWithStdin(stdinString, "proj", "create", "-f", "-", "--upsert") assert.NoError(t, err) - proj, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + proj, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.NoError(t, err) assert.Equal(t, newDescription, proj.Spec.Description) } @@ -96,14 +96,14 @@ func TestProjectDeletion(t *testing.T) { fixture.EnsureCleanState(t) projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10) - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Create( + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create( context.Background(), &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}, metav1.CreateOptions{}) assert.NoError(t, err) _, err = fixture.RunCli("proj", "delete", projectName) assert.NoError(t, err) - _, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + _, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.True(t, errors.IsNotFound(err)) assertProjHasEvent(t, proj, "delete", argo.EventReasonResourceDeleted) } @@ -112,7 +112,7 @@ func TestSetProject(t *testing.T) { fixture.EnsureCleanState(t) projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10) - _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Create( + _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create( context.Background(), &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}, metav1.CreateOptions{}) assert.NoError(t, err) @@ -123,7 +123,7 @@ func TestSetProject(t *testing.T) { "--orphaned-resources-warn=false") assert.NoError(t, err) - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.NoError(t, err) assert.Equal(t, projectName, proj.Name) assert.Equal(t, 2, len(proj.Spec.Destinations)) @@ -144,7 +144,7 @@ func TestAddProjectDestination(t *testing.T) { fixture.EnsureCleanState(t) projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10) - _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Create( + _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create( context.Background(), &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}, metav1.CreateOptions{}) if err != nil { t.Fatalf("Unable to create project %v", err) @@ -180,7 +180,7 @@ func TestAddProjectDestination(t *testing.T) { assert.Error(t, err) assert.True(t, strings.Contains(err.Error(), "namespace has an invalid format, '!*'")) - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.NoError(t, err) assert.Equal(t, projectName, proj.Name) assert.Equal(t, 1, len(proj.Spec.Destinations)) @@ -194,7 +194,7 @@ func TestAddProjectDestinationWithName(t *testing.T) { fixture.EnsureCleanState(t) projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10) - _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Create( + _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create( context.Background(), &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}, metav1.CreateOptions{}) if err != nil { t.Fatalf("Unable to create project %v", err) @@ -210,7 +210,7 @@ func TestAddProjectDestinationWithName(t *testing.T) { t.Fatalf("Unable to add project destination %v", err) } - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.NoError(t, err) assert.Equal(t, projectName, proj.Name) assert.Equal(t, 1, len(proj.Spec.Destinations)) @@ -225,7 +225,7 @@ func TestRemoveProjectDestination(t *testing.T) { fixture.EnsureCleanState(t) projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10) - _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Create(context.Background(), &v1alpha1.AppProject{ + _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(context.Background(), &v1alpha1.AppProject{ ObjectMeta: metav1.ObjectMeta{Name: projectName}, Spec: v1alpha1.AppProjectSpec{ Destinations: []v1alpha1.ApplicationDestination{{ @@ -255,7 +255,7 @@ func TestRemoveProjectDestination(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "does not exist") - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) if err != nil { t.Fatalf("Unable to get project %v", err) } @@ -268,7 +268,7 @@ func TestAddProjectSource(t *testing.T) { fixture.EnsureCleanState(t) projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10) - _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Create( + _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create( context.Background(), &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}, metav1.CreateOptions{}) if err != nil { t.Fatalf("Unable to create project %v", err) @@ -283,7 +283,7 @@ func TestAddProjectSource(t *testing.T) { _, err = fixture.RunCli("proj", "add-source", projectName, "https://github.com/argoproj/argo-cd.git") assert.Nil(t, err) - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.NoError(t, err) assert.Equal(t, projectName, proj.Name) assert.Equal(t, 1, len(proj.Spec.SourceRepos)) @@ -295,7 +295,7 @@ func TestRemoveProjectSource(t *testing.T) { fixture.EnsureCleanState(t) projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10) - _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Create(context.Background(), &v1alpha1.AppProject{ + _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(context.Background(), &v1alpha1.AppProject{ ObjectMeta: metav1.ObjectMeta{Name: projectName}, Spec: v1alpha1.AppProjectSpec{ SourceRepos: []string{"https://github.com/argoproj/argo-cd.git"}, @@ -311,7 +311,7 @@ func TestRemoveProjectSource(t *testing.T) { _, err = fixture.RunCli("proj", "remove-source", projectName, "https://github.com/argoproj/argo-cd.git") assert.NoError(t, err) - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.NoError(t, err) assert.Equal(t, projectName, proj.Name) assert.Equal(t, 0, len(proj.Spec.SourceRepos)) @@ -335,24 +335,24 @@ func TestUseJWTToken(t *testing.T) { }, Destination: v1alpha1.ApplicationDestination{ Server: v1alpha1.KubernetesInternalAPIServerAddr, - Namespace: fixture.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), }, Project: projectName, }, } - _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Create(context.Background(), &v1alpha1.AppProject{ + _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(context.Background(), &v1alpha1.AppProject{ ObjectMeta: metav1.ObjectMeta{Name: projectName}, Spec: v1alpha1.AppProjectSpec{ Destinations: []v1alpha1.ApplicationDestination{{ Server: v1alpha1.KubernetesInternalAPIServerAddr, - Namespace: fixture.ArgoCDNamespace, + Namespace: fixture.TestNamespace(), }}, SourceRepos: []string{"*"}, }, }, metav1.CreateOptions{}) assert.Nil(t, err) - _, err = fixture.AppClientset.ArgoprojV1alpha1().Applications(fixture.ArgoCDNamespace).Create(context.Background(), testApp, metav1.CreateOptions{}) + _, err = fixture.AppClientset.ArgoprojV1alpha1().Applications(fixture.TestNamespace()).Create(context.Background(), testApp, metav1.CreateOptions{}) assert.NoError(t, err) _, err = fixture.RunCli("proj", "role", "create", projectName, roleName) @@ -370,7 +370,7 @@ func TestUseJWTToken(t *testing.T) { assert.NoError(t, err) } - newProj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + newProj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.NoError(t, err) assert.Len(t, newProj.Status.JWTTokensByRole[roleName].Items, 1) assert.ElementsMatch(t, newProj.Status.JWTTokensByRole[roleName].Items, newProj.Spec.Roles[0].JWTTokens) @@ -381,7 +381,7 @@ func TestUseJWTToken(t *testing.T) { _, err = fixture.RunCli("proj", "role", "delete-token", projectName, roleName, strconv.FormatInt(newProj.Status.JWTTokensByRole[roleName].Items[0].IssuedAt, 10)) assert.NoError(t, err) - newProj, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + newProj, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.NoError(t, err) assert.Nil(t, newProj.Status.JWTTokensByRole[roleName].Items) assert.Nil(t, newProj.Spec.Roles[0].JWTTokens) @@ -392,7 +392,7 @@ func TestAddOrphanedIgnore(t *testing.T) { fixture.EnsureCleanState(t) projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10) - _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Create( + _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create( context.Background(), &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}, metav1.CreateOptions{}) if err != nil { t.Fatalf("Unable to create project %v", err) @@ -418,7 +418,7 @@ func TestAddOrphanedIgnore(t *testing.T) { assert.Error(t, err) assert.True(t, strings.Contains(err.Error(), "already defined")) - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.NoError(t, err) assert.Equal(t, projectName, proj.Name) assert.Equal(t, 1, len(proj.Spec.OrphanedResources.Ignore)) @@ -433,11 +433,11 @@ func TestRemoveOrphanedIgnore(t *testing.T) { fixture.EnsureCleanState(t) projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10) - _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Create(context.Background(), &v1alpha1.AppProject{ + _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(context.Background(), &v1alpha1.AppProject{ 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"}}, }, }, @@ -467,7 +467,7 @@ func TestRemoveOrphanedIgnore(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "does not exist") - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) if err != nil { t.Fatalf("Unable to get project %v", err) } @@ -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", @@ -489,7 +489,7 @@ func createAndConfigGlobalProject() error { return err } - projGlobal, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectGlobalName, metav1.GetOptions{}) + projGlobal, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectGlobalName, metav1.GetOptions{}) if err != nil { return err } @@ -514,12 +514,12 @@ func createAndConfigGlobalProject() error { win := &v1alpha1.SyncWindow{Kind: "deny", Schedule: "* * * * *", Duration: "1h", Applications: []string{"*"}} projGlobal.Spec.SyncWindows = append(projGlobal.Spec.SyncWindows, win) - _, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Update(context.Background(), projGlobal, metav1.UpdateOptions{}) + _, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Update(context.Background(), projGlobal, metav1.UpdateOptions{}) if err != nil { return err } - //Configure global project settings + // Configure global project settings globalProjectsSettings := `data: accounts.config-service: apiKey globalProjects: | @@ -533,7 +533,7 @@ func createAndConfigGlobalProject() error { projectName: %s` _, err = fixture.Run("", "kubectl", "patch", "cm", "argocd-cm", - "-n", fixture.ArgoCDNamespace, + "-n", fixture.TestNamespace(), "-p", fmt.Sprintf(globalProjectsSettings, projGlobal.Name)) if err != nil { return err @@ -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", @@ -556,10 +556,10 @@ func TestGetVirtualProjectNoMatch(t *testing.T) { "--orphaned-resources") assert.NoError(t, err) - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + 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", @@ -592,15 +592,15 @@ func TestGetVirtualProjectMatch(t *testing.T) { "--orphaned-resources") assert.NoError(t, err) - proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(context.Background(), projectName, metav1.GetOptions{}) + 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.ArgoCDNamespace).Update(context.Background(), proj, metav1.UpdateOptions{}) + _, 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/repo_creds_test.go b/test/e2e/repo_creds_test.go index b4772698675dc..59df113605a7b 100644 --- a/test/e2e/repo_creds_test.go +++ b/test/e2e/repo_creds_test.go @@ -57,7 +57,7 @@ func TestCanAddAppFromInsecurePrivateRepoWithCredCfg(t *testing.T) { And(func() { secretName := fixture.CreateSecret(fixture.GitUsername, fixture.GitPassword) FailOnErr(fixture.Run("", "kubectl", "patch", "cm", "argocd-cm", - "-n", fixture.ArgoCDNamespace, + "-n", fixture.TestNamespace(), "-p", fmt.Sprintf( `{"data": {"repository.credentials": "- passwordSecret:\n key: password\n name: %s\n url: %s\n insecure: true\n usernameSecret:\n key: username\n name: %s\n"}}`, secretName, @@ -83,7 +83,7 @@ func TestCanAddAppFromPrivateRepoWithCredCfg(t *testing.T) { And(func() { secretName := fixture.CreateSecret(fixture.GitUsername, fixture.GitPassword) FailOnErr(fixture.Run("", "kubectl", "patch", "cm", "argocd-cm", - "-n", fixture.ArgoCDNamespace, + "-n", fixture.TestNamespace(), "-p", fmt.Sprintf( `{"data": {"repository.credentials": "- passwordSecret:\n key: password\n name: %s\n url: %s\n usernameSecret:\n key: username\n name: %s\n"}}`, secretName, @@ -108,7 +108,7 @@ func TestCanAddAppFromClientCertRepoWithCredCfg(t *testing.T) { And(func() { secretName := fixture.CreateSecret(fixture.GitUsername, fixture.GitPassword) FailOnErr(fixture.Run("", "kubectl", "patch", "cm", "argocd-cm", - "-n", fixture.ArgoCDNamespace, + "-n", fixture.TestNamespace(), "-p", fmt.Sprintf( `{"data": {"repository.credentials": "- passwordSecret:\n key: password\n name: %s\n url: %s\n usernameSecret:\n key: username\n name: %s\n"}}`, secretName, diff --git a/test/e2e/repo_management_test.go b/test/e2e/repo_management_test.go index 30b304c8b7b2e..70b14d5682299 100644 --- a/test/e2e/repo_management_test.go +++ b/test/e2e/repo_management_test.go @@ -7,9 +7,11 @@ import ( "github.com/stretchr/testify/assert" repositorypkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/repository" + "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" "github.com/argoproj/argo-cd/v2/test/e2e/fixture/repos" + . "github.com/argoproj/argo-cd/v2/util/errors" argoio "github.com/argoproj/argo-cd/v2/util/io" "github.com/argoproj/argo-cd/v2/util/settings" ) @@ -52,6 +54,38 @@ func TestAddRemovePublicRepo(t *testing.T) { }) } +func TestGetRepoWithInheritedCreds(t *testing.T) { + app.Given(t).And(func() { + // create repo credentials + FailOnErr(fixture.RunCli("repocreds", "add", fixture.RepoURL(fixture.RepoURLTypeHTTPSOrg), "--github-app-id", fixture.GithubAppID, "--github-app-installation-id", fixture.GithubAppInstallationID, "--github-app-private-key-path", repos.CertKeyPath)) + + repoUrl := fixture.RepoURL(fixture.RepoURLTypeHTTPS) + + // Hack: First we need to create repo with valid credentials + FailOnErr(fixture.RunCli("repo", "add", repoUrl, "--username", fixture.GitUsername, "--password", fixture.GitPassword, "--insecure-skip-server-verification")) + + // Then, we remove username/password so that the repo inherits the credentials from our repocreds + conn, repoClient, err := fixture.ArgoCDClientset.NewRepoClient() + assert.NoError(t, err) + defer argoio.Close(conn) + + _, err = repoClient.UpdateRepository(context.Background(), &repositorypkg.RepoUpdateRequest{ + Repo: &v1alpha1.Repository{ + Repo: repoUrl, + }, + }) + assert.NoError(t, err) + + // CLI output should indicate that repo has inherited credentials + out, err := fixture.RunCli("repo", "get", repoUrl) + assert.NoError(t, err) + assert.Contains(t, out, "inherited") + + _, err = fixture.RunCli("repo", "rm", repoUrl) + assert.NoError(t, err) + }) +} + func TestUpsertExistingRepo(t *testing.T) { app.Given(t).And(func() { fixture.SetRepos(settings.RepositoryCredentials{URL: fixture.RepoURL(fixture.RepoURLTypeFile)}) diff --git a/test/e2e/selective_sync_test.go b/test/e2e/selective_sync_test.go index 1738264c509fc..491914be55184 100644 --- a/test/e2e/selective_sync_test.go +++ b/test/e2e/selective_sync_test.go @@ -80,7 +80,7 @@ func TestSelectiveSyncWithoutNamespace(t *testing.T) { Expect(ResourceSyncStatusWithNamespaceIs("Deployment", "guestbook-ui", fixture.DeploymentNamespace(), SyncStatusCodeSynced)) } -//In selectedResource to sync, namespace is provided +// In selectedResource to sync, namespace is provided func TestSelectiveSyncWithNamespace(t *testing.T) { selectedResourceNamespace := getNewNamespace(t) defer func() { diff --git a/test/e2e/sync_options_test.go b/test/e2e/sync_options_test.go index 657c8b117705b..3eb7140787097 100644 --- a/test/e2e/sync_options_test.go +++ b/test/e2e/sync_options_test.go @@ -80,6 +80,29 @@ func TestSyncWithStatusIgnored(t *testing.T) { Expect(SyncStatusIs(SyncStatusCodeSynced)) } +func TestSyncWithApplyOutOfSyncOnly(t *testing.T) { + var ns string + Given(t). + Path(guestbookPath). + ApplyOutOfSyncOnly(). + When(). + CreateFromFile(func(app *Application) { + ns = app.Spec.Destination.Namespace + }). + Then(). + Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). + When(). + Sync(). + Then(). + When(). + PatchFile("guestbook-ui-deployment.yaml", `[{ "op": "replace", "path": "/spec/replicas", "value": 1 }]`). + Sync(). + Then(). + // Only one resource should be in sync result + Expect(ResourceResultNumbering(1)). + Expect(ResourceResultIs(ResourceResult{Group: "apps", Version: "v1", Kind: "Deployment", Namespace: ns, Name: "guestbook-ui", Message: "deployment.apps/guestbook-ui configured", SyncPhase: SyncPhaseSync, HookPhase: OperationRunning, Status: ResultCodeSynced})) +} + func TestSyncWithSkipHook(t *testing.T) { fixture.SkipOnEnv(t, "OPENSHIFT") Given(t). 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/cluster-role-hook/cluster-role.yaml b/test/e2e/testdata/cluster-role-hook/cluster-role.yaml new file mode 100644 index 0000000000000..456e1b12fbd33 --- /dev/null +++ b/test/e2e/testdata/cluster-role-hook/cluster-role.yaml @@ -0,0 +1,15 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + namespace: cert-manager + name: my-cluster-role-binding + annotations: + argocd.argoproj.io/hook: PreSync +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: default + namespace: default diff --git a/test/e2e/testdata/cluster-role/pod.yaml b/test/e2e/testdata/cluster-role-hook/pod.yaml similarity index 100% rename from test/e2e/testdata/cluster-role/pod.yaml rename to test/e2e/testdata/cluster-role-hook/pod.yaml diff --git a/test/e2e/testdata/cluster-role/cluster-role.yaml b/test/e2e/testdata/cluster-role/cluster-role.yaml index cb6cd7c1b3e42..cc5365bb3f4de 100644 --- a/test/e2e/testdata/cluster-role/cluster-role.yaml +++ b/test/e2e/testdata/cluster-role/cluster-role.yaml @@ -1,10 +1,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - namespace: cert-manager name: my-cluster-role-binding - annotations: - argocd.argoproj.io/hook: PreSync roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole @@ -12,4 +9,4 @@ roleRef: subjects: - kind: ServiceAccount name: default - namespace: default \ No newline at end of file + namespace: default diff --git a/test/e2e/testdata/cmp-fileName/plugin.yaml b/test/e2e/testdata/cmp-fileName/plugin.yaml index 766278c79e773..b3f8068de2100 100644 --- a/test/e2e/testdata/cmp-fileName/plugin.yaml +++ b/test/e2e/testdata/cmp-fileName/plugin.yaml @@ -5,6 +5,6 @@ metadata: spec: version: v1.0 generate: - command: [sh, -c, 'echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"Foo\": \"$FOO\", \"KubeVersion\": \"$KUBE_VERSION\", \"KubeApiVersion\": \"$KUBE_API_VERSIONS\",\"Bar\": \"baz\"}}}"'] + command: [sh, -c, 'echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"Foo\": \"$ARGOCD_ENV_FOO\", \"KubeVersion\": \"$KUBE_VERSION\", \"KubeApiVersion\": \"$KUBE_API_VERSIONS\",\"Bar\": \"baz\"}}}"'] discover: fileName: "subdir/s*.yaml" diff --git a/test/e2e/testdata/cmp-gitcreds/plugin.yaml b/test/e2e/testdata/cmp-gitcreds/plugin.yaml new file mode 100644 index 0000000000000..024804f495cc9 --- /dev/null +++ b/test/e2e/testdata/cmp-gitcreds/plugin.yaml @@ -0,0 +1,10 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ConfigManagementPlugin +metadata: + name: cmp-gitcreds +spec: + version: v1.0 + generate: + command: [sh, -c, 'echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"GitAskpass\": \"$GIT_ASKPASS\"}}}"'] + discover: + fileName: "subdir/s*.yaml" diff --git a/test/e2e/testdata/cmp-gitcreds/subdir/special.yaml b/test/e2e/testdata/cmp-gitcreds/subdir/special.yaml new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/test/e2e/testdata/cmp-gitcredstemplate/plugin.yaml b/test/e2e/testdata/cmp-gitcredstemplate/plugin.yaml new file mode 100644 index 0000000000000..e57ee747bd078 --- /dev/null +++ b/test/e2e/testdata/cmp-gitcredstemplate/plugin.yaml @@ -0,0 +1,10 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ConfigManagementPlugin +metadata: + name: cmp-gitcredstemplate +spec: + version: v1.0 + generate: + command: [sh, -c, 'echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"GitAskpass\": \"$GIT_ASKPASS\", \"GitUsername\": \"$GIT_USERNAME\", \"GitPassword\": \"$GIT_PASSWORD\"}}}"'] + discover: + fileName: "subdir/s*.yaml" diff --git a/test/e2e/testdata/cmp-gitcredstemplate/subdir/special.yaml b/test/e2e/testdata/cmp-gitcredstemplate/subdir/special.yaml new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/test/e2e/testdata/cmp-kustomize/plugin.yaml b/test/e2e/testdata/cmp-kustomize/plugin.yaml new file mode 100644 index 0000000000000..3cdcc6d643758 --- /dev/null +++ b/test/e2e/testdata/cmp-kustomize/plugin.yaml @@ -0,0 +1,10 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ConfigManagementPlugin +metadata: + name: cmp-kustomize +spec: + version: v1.0 + generate: + command: [kustomize, build, .] + discover: + fileName: "kustomization.yaml" diff --git a/test/e2e/testdata/cmp-preserve-file-mode/plugin.yaml b/test/e2e/testdata/cmp-preserve-file-mode/plugin.yaml new file mode 100644 index 0000000000000..c522649234e88 --- /dev/null +++ b/test/e2e/testdata/cmp-preserve-file-mode/plugin.yaml @@ -0,0 +1,11 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ConfigManagementPlugin +metadata: + name: cmp-preserve-file-mode +spec: + version: v1.0 + generate: + command: [sh, -c , "./script.sh"] + discovery: + - glob: "**/*" + preserveFileMode: true diff --git a/test/e2e/testdata/cmp-preserve-file-mode/script.sh b/test/e2e/testdata/cmp-preserve-file-mode/script.sh new file mode 100755 index 0000000000000..1fbb8fde0c14d --- /dev/null +++ b/test/e2e/testdata/cmp-preserve-file-mode/script.sh @@ -0,0 +1,8 @@ +cat << EOF +apiVersion: v1 +kind: ConfigMap +metadata: + name: test-cm +data: + foo: bar +EOF \ No newline at end of file diff --git a/test/e2e/testdata/crashing-guestbook/kustomization.yaml b/test/e2e/testdata/crashing-guestbook/kustomization.yaml index b9ed6ab1a34f0..1c10225ce38b1 100644 --- a/test/e2e/testdata/crashing-guestbook/kustomization.yaml +++ b/test/e2e/testdata/crashing-guestbook/kustomization.yaml @@ -1,8 +1,8 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -bases: +resources: - ../guestbook patches: - - guestbook-deployment.yaml + - path: guestbook-deployment.yaml diff --git a/test/e2e/testdata/crd-version-differences/crd-does-not-exist-instance.yaml b/test/e2e/testdata/crd-version-differences/crd-does-not-exist-instance.yaml new file mode 100644 index 0000000000000..ba753eedda6a4 --- /dev/null +++ b/test/e2e/testdata/crd-version-differences/crd-does-not-exist-instance.yaml @@ -0,0 +1,7 @@ +apiVersion: argoproj.io/v1alpha1 +kind: DoesNotExist +metadata: + name: dummy-crd-instance-doesnotexist +spec: + cpu: 2000m + memory: 32Mi diff --git a/test/e2e/testdata/crd-version-differences/crd-v1alpha1.yaml b/test/e2e/testdata/crd-version-differences/crd-v1alpha1.yaml new file mode 100644 index 0000000000000..3cf492a837979 --- /dev/null +++ b/test/e2e/testdata/crd-version-differences/crd-v1alpha1.yaml @@ -0,0 +1,35 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: fakes.argoproj.io +spec: + conversion: + strategy: None + group: argoproj.io + names: + kind: Fake + listKind: FakeList + plural: fakes + singular: fake + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + apiVersion: + type: string + kind: + type: string + metadata: + type: object + spec: + type: object + properties: + cpu: + type: string + memory: + type: string diff --git a/test/e2e/testdata/crd-version-differences/crd-v1alpha2-instance.yaml b/test/e2e/testdata/crd-version-differences/crd-v1alpha2-instance.yaml new file mode 100644 index 0000000000000..987ee4bd0e3e2 --- /dev/null +++ b/test/e2e/testdata/crd-version-differences/crd-v1alpha2-instance.yaml @@ -0,0 +1,7 @@ +apiVersion: argoproj.io/v1alpha2 +kind: Fake +metadata: + name: fake-crd-instance +spec: + cpu: 2000m + memory: 32Mi diff --git a/test/e2e/testdata/crd-version-differences/crd-wronggroup-instance.yaml b/test/e2e/testdata/crd-version-differences/crd-wronggroup-instance.yaml new file mode 100644 index 0000000000000..95e022e046897 --- /dev/null +++ b/test/e2e/testdata/crd-version-differences/crd-wronggroup-instance.yaml @@ -0,0 +1,7 @@ +apiVersion: wrong.group/v1alpha1 +kind: Fake +metadata: + name: fake-crd-instance-wronggroup +spec: + cpu: 2000m + memory: 32Mi diff --git a/test/e2e/testdata/deprecated-extensions/deployment.yaml b/test/e2e/testdata/deprecated-extensions/deployment.yaml index 5593c3157fc57..bc4ef128d8bf4 100644 --- a/test/e2e/testdata/deprecated-extensions/deployment.yaml +++ b/test/e2e/testdata/deprecated-extensions/deployment.yaml @@ -1,4 +1,4 @@ -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: extensions-deployment diff --git a/test/e2e/testdata/git-submodule/submodule-pod.yaml b/test/e2e/testdata/git-submodule/submodule-pod.yaml index fa3b92c2f5875..134107da31cba 100644 --- a/test/e2e/testdata/git-submodule/submodule-pod.yaml +++ b/test/e2e/testdata/git-submodule/submodule-pod.yaml @@ -7,6 +7,4 @@ spec: - name: main image: quay.io/argoprojlabs/argocd-e2e-container:0.1 imagePullPolicy: IfNotPresent - command: - - "true" - restartPolicy: Never + terminationGracePeriodSeconds: 0 diff --git a/test/e2e/testdata/guestbook-with-plain-namespace-manifest/guestbook-ui-deployment.yaml b/test/e2e/testdata/guestbook-with-plain-namespace-manifest/guestbook-ui-deployment.yaml new file mode 100644 index 0000000000000..bf3375672f70c --- /dev/null +++ b/test/e2e/testdata/guestbook-with-plain-namespace-manifest/guestbook-ui-deployment.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: guestbook-ui + labels: + test: "true" +spec: + replicas: 0 + revisionHistoryLimit: 3 + selector: + matchLabels: + app: guestbook-ui + template: + metadata: + labels: + app: guestbook-ui + spec: + containers: + - image: quay.io/argoprojlabs/argocd-e2e-container:0.2 + imagePullPolicy: IfNotPresent + name: guestbook-ui + ports: + - containerPort: 80 diff --git a/test/e2e/testdata/guestbook-with-plain-namespace-manifest/guestbook-ui-namespace.yaml b/test/e2e/testdata/guestbook-with-plain-namespace-manifest/guestbook-ui-namespace.yaml new file mode 100644 index 0000000000000..ceda849716ccb --- /dev/null +++ b/test/e2e/testdata/guestbook-with-plain-namespace-manifest/guestbook-ui-namespace.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: guestbook-ui-with-namespace-manifest + labels: + test: "true" + annotations: + foo: bar + something: else diff --git a/test/e2e/testdata/guestbook-with-plain-namespace-manifest/guestbook-ui-svc.yaml b/test/e2e/testdata/guestbook-with-plain-namespace-manifest/guestbook-ui-svc.yaml new file mode 100644 index 0000000000000..e8a4a27fbae40 --- /dev/null +++ b/test/e2e/testdata/guestbook-with-plain-namespace-manifest/guestbook-ui-svc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Service +metadata: + name: guestbook-ui +spec: + ports: + - port: 80 + targetPort: 80 + selector: + app: guestbook-ui diff --git a/test/e2e/testdata/helm-with-multiple-dependencies-permission-denied/Chart.yaml b/test/e2e/testdata/helm-with-multiple-dependencies-permission-denied/Chart.yaml new file mode 100644 index 0000000000000..72f36221ea482 --- /dev/null +++ b/test/e2e/testdata/helm-with-multiple-dependencies-permission-denied/Chart.yaml @@ -0,0 +1,11 @@ +apiVersion: v2 +name: helm-with-multiple-dependencies-permission-denied +version: v1.0.0 +dependencies: + - name: helm + repository: "https://localhost:9443/argo-e2e/testdata.git/helm-repo/local" + version: v1.0.0 + - name: helm + repository: "https://localhost:9443/argo-e2e/testdata.git/helm-repo/local2" + version: v1.0.0 + alias: helm2 \ No newline at end of file diff --git a/test/e2e/testdata/helm-with-multiple-dependencies/Chart.yaml b/test/e2e/testdata/helm-with-multiple-dependencies/Chart.yaml index fc1982761746c..f7f144d20e123 100644 --- a/test/e2e/testdata/helm-with-multiple-dependencies/Chart.yaml +++ b/test/e2e/testdata/helm-with-multiple-dependencies/Chart.yaml @@ -1,7 +1,11 @@ apiVersion: v2 -name: helm-with-dependencies +name: helm-with-multiple-dependencies version: v1.0.0 dependencies: - name: helm repository: "https://localhost:9444/argo-e2e/testdata.git/helm-repo/local" version: v1.0.0 + - name: helm + repository: "https://localhost:9444/argo-e2e/testdata.git/helm-repo/local2" + version: v1.0.0 + alias: helm2 \ No newline at end of file diff --git a/test/e2e/testdata/hook-custom-health/kustomization.yaml b/test/e2e/testdata/hook-custom-health/kustomization.yaml index 3c88ce9216652..7af040cfb6edb 100644 --- a/test/e2e/testdata/hook-custom-health/kustomization.yaml +++ b/test/e2e/testdata/hook-custom-health/kustomization.yaml @@ -1,8 +1,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -bases: - - ../guestbook - resources: + - ../guestbook - config-map.yaml \ No newline at end of file diff --git a/test/e2e/testdata/https-kustomize-base/local/kustomization.yaml b/test/e2e/testdata/https-kustomize-base/local/kustomization.yaml index da7f7e8e01e99..d7c6dafc34df3 100644 --- a/test/e2e/testdata/https-kustomize-base/local/kustomization.yaml +++ b/test/e2e/testdata/https-kustomize-base/local/kustomization.yaml @@ -1,7 +1,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -bases: +resources: - https://localhost:9443/argo-e2e/testdata.git//guestbook namePrefix: child- \ No newline at end of file diff --git a/test/e2e/testdata/https-kustomize-base/remote/kustomization.yaml b/test/e2e/testdata/https-kustomize-base/remote/kustomization.yaml index 96e9885a84cba..f3d27c1f258c9 100644 --- a/test/e2e/testdata/https-kustomize-base/remote/kustomization.yaml +++ b/test/e2e/testdata/https-kustomize-base/remote/kustomization.yaml @@ -1,7 +1,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -bases: +resources: - https://argocd-e2e-server:9443/argo-e2e/testdata.git//guestbook namePrefix: child- diff --git a/test/e2e/testdata/multi-namespace/deployment-with-namespace.yaml b/test/e2e/testdata/multi-namespace/deployment-with-namespace.yaml index 474e117ac487c..ebd3e77f679e6 100644 --- a/test/e2e/testdata/multi-namespace/deployment-with-namespace.yaml +++ b/test/e2e/testdata/multi-namespace/deployment-with-namespace.yaml @@ -1,4 +1,4 @@ -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: helm-guestbook diff --git a/test/e2e/testdata/multi-namespace/deployment.yaml b/test/e2e/testdata/multi-namespace/deployment.yaml index 08d30228fad03..bd6f69aadd7e8 100644 --- a/test/e2e/testdata/multi-namespace/deployment.yaml +++ b/test/e2e/testdata/multi-namespace/deployment.yaml @@ -1,4 +1,4 @@ -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: helm-guestbook 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/resource-actions/cron-job.yaml b/test/e2e/testdata/resource-actions/cron-job.yaml new file mode 100644 index 0000000000000..3ab1fb9b1cd8a --- /dev/null +++ b/test/e2e/testdata/resource-actions/cron-job.yaml @@ -0,0 +1,19 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: hello +spec: + schedule: "* * * * *" + jobTemplate: + spec: + template: + spec: + containers: + - name: hello + image: busybox:1.28 + imagePullPolicy: IfNotPresent + command: + - /bin/sh + - -c + - date; echo Hello from the Kubernetes cluster + restartPolicy: OnFailure \ No newline at end of file diff --git a/test/e2e/testdata/ssh-kustomize-base/local/kustomization.yaml b/test/e2e/testdata/ssh-kustomize-base/local/kustomization.yaml index 56275b107b876..6c63e526ef842 100644 --- a/test/e2e/testdata/ssh-kustomize-base/local/kustomization.yaml +++ b/test/e2e/testdata/ssh-kustomize-base/local/kustomization.yaml @@ -1,5 +1,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -bases: +resources: - ssh://root@localhost:2222/tmp/argo-e2e/testdata.git//config-map diff --git a/test/e2e/testdata/ssh-kustomize-base/remote/kustomization.yaml b/test/e2e/testdata/ssh-kustomize-base/remote/kustomization.yaml index 84537aac69f81..c144aa21a1cee 100644 --- a/test/e2e/testdata/ssh-kustomize-base/remote/kustomization.yaml +++ b/test/e2e/testdata/ssh-kustomize-base/remote/kustomization.yaml @@ -1,5 +1,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -bases: +resources: - ssh://root@argocd-e2e-server:2222/tmp/argo-e2e/testdata.git//config-map 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/e2e/testdata2/cmp-symlink/plugin.yaml b/test/e2e/testdata2/cmp-symlink/plugin.yaml new file mode 100644 index 0000000000000..848deaeab3d28 --- /dev/null +++ b/test/e2e/testdata2/cmp-symlink/plugin.yaml @@ -0,0 +1,13 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ConfigManagementPlugin +metadata: + name: cmp-symlink +spec: + version: v1.0 + init: + command: [kustomize, version] + generate: + command: [sh, -c, 'kustomize edit set image test=quay.io/argoprojlabs/argocd-e2e-container:0.2 && kustomize build --load-restrictor LoadRestrictionsNone'] + discover: + find: + glob: "**/kustomization.yaml" diff --git a/test/e2e/testdata2/guestbook-partial-symlink-files/guestbook-ui-deployment.yaml b/test/e2e/testdata2/guestbook-partial-symlink-files/guestbook-ui-deployment.yaml new file mode 120000 index 0000000000000..ee9a72011e097 --- /dev/null +++ b/test/e2e/testdata2/guestbook-partial-symlink-files/guestbook-ui-deployment.yaml @@ -0,0 +1 @@ +../guestbook/guestbook-ui-deployment.yaml \ No newline at end of file diff --git a/test/e2e/testdata2/guestbook-partial-symlink-files/guestbook-ui-svc.yaml b/test/e2e/testdata2/guestbook-partial-symlink-files/guestbook-ui-svc.yaml new file mode 100644 index 0000000000000..e8a4a27fbae40 --- /dev/null +++ b/test/e2e/testdata2/guestbook-partial-symlink-files/guestbook-ui-svc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Service +metadata: + name: guestbook-ui +spec: + ports: + - port: 80 + targetPort: 80 + selector: + app: guestbook-ui diff --git a/test/e2e/testdata2/guestbook-partial-symlink-files/kustomization.yaml b/test/e2e/testdata2/guestbook-partial-symlink-files/kustomization.yaml new file mode 100644 index 0000000000000..ff46a361352b4 --- /dev/null +++ b/test/e2e/testdata2/guestbook-partial-symlink-files/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ./guestbook-ui-deployment.yaml + - ./guestbook-ui-svc.yaml diff --git a/test/e2e/testdata2/guestbook-symlink-files/guestbook-ui-deployment.yaml b/test/e2e/testdata2/guestbook-symlink-files/guestbook-ui-deployment.yaml new file mode 120000 index 0000000000000..ee9a72011e097 --- /dev/null +++ b/test/e2e/testdata2/guestbook-symlink-files/guestbook-ui-deployment.yaml @@ -0,0 +1 @@ +../guestbook/guestbook-ui-deployment.yaml \ No newline at end of file diff --git a/test/e2e/testdata2/guestbook-symlink-files/guestbook-ui-svc.yaml b/test/e2e/testdata2/guestbook-symlink-files/guestbook-ui-svc.yaml new file mode 120000 index 0000000000000..9dc306132bcb3 --- /dev/null +++ b/test/e2e/testdata2/guestbook-symlink-files/guestbook-ui-svc.yaml @@ -0,0 +1 @@ +../guestbook/guestbook-ui-svc.yaml \ No newline at end of file diff --git a/test/e2e/testdata2/guestbook-symlink-files/kustomization.yaml b/test/e2e/testdata2/guestbook-symlink-files/kustomization.yaml new file mode 120000 index 0000000000000..339635a9669f0 --- /dev/null +++ b/test/e2e/testdata2/guestbook-symlink-files/kustomization.yaml @@ -0,0 +1 @@ +../guestbook/kustomization.yaml \ No newline at end of file diff --git a/test/e2e/testdata2/guestbook-symlink-folder b/test/e2e/testdata2/guestbook-symlink-folder new file mode 120000 index 0000000000000..3132c00309c3a --- /dev/null +++ b/test/e2e/testdata2/guestbook-symlink-folder @@ -0,0 +1 @@ +guestbook \ No newline at end of file diff --git a/test/e2e/testdata2/guestbook/guestbook-ui-deployment.yaml b/test/e2e/testdata2/guestbook/guestbook-ui-deployment.yaml new file mode 100644 index 0000000000000..2e748234df4a4 --- /dev/null +++ b/test/e2e/testdata2/guestbook/guestbook-ui-deployment.yaml @@ -0,0 +1,23 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: guestbook-ui + labels: + test: "true" +spec: + replicas: 0 + revisionHistoryLimit: 3 + selector: + matchLabels: + app: guestbook-ui + template: + metadata: + labels: + app: guestbook-ui + spec: + containers: + - image: test + imagePullPolicy: IfNotPresent + name: guestbook-ui + ports: + - containerPort: 80 diff --git a/test/e2e/testdata2/guestbook/guestbook-ui-svc.yaml b/test/e2e/testdata2/guestbook/guestbook-ui-svc.yaml new file mode 100644 index 0000000000000..e8a4a27fbae40 --- /dev/null +++ b/test/e2e/testdata2/guestbook/guestbook-ui-svc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: Service +metadata: + name: guestbook-ui +spec: + ports: + - port: 80 + targetPort: 80 + selector: + app: guestbook-ui diff --git a/test/e2e/testdata2/guestbook/kustomization.yaml b/test/e2e/testdata2/guestbook/kustomization.yaml new file mode 100644 index 0000000000000..ff46a361352b4 --- /dev/null +++ b/test/e2e/testdata2/guestbook/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - ./guestbook-ui-deployment.yaml + - ./guestbook-ui-svc.yaml diff --git a/test/fixture/testrepos/start-git.sh b/test/fixture/testrepos/start-git.sh index b36da58a28388..4a660c29a7575 100755 --- a/test/fixture/testrepos/start-git.sh +++ b/test/fixture/testrepos/start-git.sh @@ -2,5 +2,5 @@ docker run --name e2e-git --rm -i \ -p 2222:2222 -p 9080:9080 -p 9443:9443 -p 9444:9444 -p 9445:9445 \ - -w /go/src/github.com/argoproj/argo-cd -v $(pwd):/go/src/github.com/argoproj/argo-cd -v /tmp:/tmp argoproj/argo-cd-ci-builder:v1.0.0 \ + -w /go/src/github.com/argoproj/argo-cd -v $(pwd):/go/src/github.com/argoproj/argo-cd -v /tmp:/tmp docker.io/argoproj/argo-cd-ci-builder:v1.0.0 \ bash -c "goreman -f ./test/fixture/testrepos/Procfile start" diff --git a/test/manifests/base/kustomization.yaml b/test/manifests/base/kustomization.yaml index 66aa10c182934..149554b317eba 100644 --- a/test/manifests/base/kustomization.yaml +++ b/test/manifests/base/kustomization.yaml @@ -1,11 +1,11 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization -bases: +resources: - ../../../manifests/crds - ../../../manifests/base/config - ../../../manifests/cluster-rbac - ../../../manifests/base/notification -patchesStrategicMerge: - - patches.yaml +patches: + - path: patches.yaml diff --git a/test/manifests/cmp/kustomization.yaml b/test/manifests/cmp/kustomization.yaml index f0f55a990250e..a2387e42f453b 100644 --- a/test/manifests/cmp/kustomization.yaml +++ b/test/manifests/cmp/kustomization.yaml @@ -5,9 +5,9 @@ resources: - plugin.yaml - app.yaml -patchesStrategicMerge: - - repo-patch.yaml - - secret-patch.yaml +patches: + - path: repo-patch.yaml + - path: secret-patch.yaml images: - name: quay.io/argoproj/argocd diff --git a/test/manifests_test.go b/test/manifests_test.go index f5959ca40d29c..ce62b175d79b3 100644 --- a/test/manifests_test.go +++ b/test/manifests_test.go @@ -16,7 +16,7 @@ func TestKustomizeVersion(t *testing.T) { test.CIOnly(t) out, err := argoexec.RunCommand("kustomize", argoexec.CmdOpts{}, "version") assert.NoError(t, err) - assert.Contains(t, out, "Version:kustomize/v4", "kustomize should be version 4") + assert.Contains(t, out, "v5.", "kustomize should be version 5") } // TestBuildManifests makes sure we are consistent in naming, and all kustomization.yamls are buildable diff --git a/test/remote/Dockerfile b/test/remote/Dockerfile index 182dc47e9e69c..cf43ee355567d 100644 --- a/test/remote/Dockerfile +++ b/test/remote/Dockerfile @@ -1,6 +1,6 @@ ARG BASE_IMAGE=docker.io/library/ubuntu:22.04 -FROM golang:1.18 AS go +FROM docker.io/library/golang:1.22.0@sha256:7b297d9abee021bab9046e492506b3c2da8a3722cbf301653186545ecc1e00bb AS go RUN go install github.com/mattn/goreman@latest && \ go install github.com/kisielk/godepgraph@latest @@ -9,21 +9,21 @@ FROM $BASE_IMAGE ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install --no-install-recommends -y \ - ca-certificates \ - curl \ - openssh-server \ - nginx \ - fcgiwrap \ - git \ - git-lfs \ - gpg \ - make \ - wget \ - gcc \ - sudo \ - zip && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + ca-certificates \ + curl \ + openssh-server \ + nginx \ + fcgiwrap \ + git \ + git-lfs \ + gpg \ + make \ + wget \ + gcc \ + sudo \ + zip && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # These are required for running end-to-end tests COPY ./test/fixture/testrepos/id_rsa.pub /root/.ssh/authorized_keys diff --git a/test/remote/Makefile b/test/remote/Makefile index 5925d3745d968..4bc9b90811b65 100644 --- a/test/remote/Makefile +++ b/test/remote/Makefile @@ -2,8 +2,8 @@ PWD=$(shell pwd) TEST_ROOT=$(shell realpath $(PWD)/../..) IMAGE_NAMESPACE?= -IMAGE_NAME=argocd-e2e-cluster -IMAGE_TAG=latest +IMAGE_NAME?=argocd-e2e-cluster +IMAGE_TAG?=latest ifneq (${IMAGE_NAMESPACE},) IMAGE_PREFIX=$(IMAGE_NAMESPACE)/ else diff --git a/test/remote/README.md b/test/remote/README.md index 25364ab61c26b..0c05dce914d32 100644 --- a/test/remote/README.md +++ b/test/remote/README.md @@ -128,7 +128,7 @@ Run the tests In another shell, do a port-forward to the API server's service: ```shell -kubectl -n argocd-e2e port-forward svc/argocd-server 443:4443 +kubectl -n argocd-e2e port-forward svc/argocd-server 4443:443 ``` Set Argo CD Server port: @@ -140,7 +140,7 @@ export ARGOCD_SERVER=127.0.0.1:4443 Set the admin password to use: ```shell -export ARGOCD_E2E_ADMIN_PASSWORD=$(kubectl get secrets argocd-initial-admin-secret -o jsonpath='{.data.password}'|base64 -d) +export ARGOCD_E2E_ADMIN_PASSWORD=$(kubectl -n argocd-e2e get secrets argocd-initial-admin-secret -o jsonpath='{.data.password}'|base64 -d) ``` Run the tests diff --git a/test/testdata.go b/test/testdata.go index 4531a11c6eb69..2c5c6178317e3 100644 --- a/test/testdata.go +++ b/test/testdata.go @@ -4,9 +4,8 @@ import ( "context" "github.com/alicebob/miniredis/v2" - "github.com/go-redis/redis/v8" - "github.com/argoproj/gitops-engine/pkg/utils/testing" + "github.com/redis/go-redis/v9" apiv1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -86,6 +85,22 @@ func NewDeployment() *unstructured.Unstructured { return testing.Unstructured(DeploymentManifest) } +var ConfigMapManifest = ` +{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": { + "name": "my-configmap", + }, + "data": { + "config.yaml": "auth: token\nconfig:field" + } +}` + +func NewConfigMap() *unstructured.Unstructured { + return testing.Unstructured(ConfigMapManifest) +} + func NewFakeConfigMap() *apiv1.ConfigMap { cm := apiv1.ConfigMap{ TypeMeta: metav1.TypeMeta{ diff --git a/test/testutil.go b/test/testutil.go index bccf0cef23a3f..e97de4a762bcf 100644 --- a/test/testutil.go +++ b/test/testutil.go @@ -1,18 +1,20 @@ package test import ( + "bytes" "context" "encoding/json" "fmt" - "log" "net" "os" "testing" "time" - "github.com/ghodss/yaml" + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/tools/cache" + "sigs.k8s.io/yaml" ) // StartInformer is a helper to start an informer, wait for its cache to sync and return a cancel func @@ -83,6 +85,15 @@ func YamlToUnstructured(yamlStr string) *unstructured.Unstructured { return &unstructured.Unstructured{Object: obj} } +func YamlToApplication(yamlStr string) *v1alpha1.Application { + app := v1alpha1.Application{} + err := yaml.Unmarshal([]byte(yamlStr), &app) + if err != nil { + panic(err) + } + return &app +} + // ToMap converts any object to a map[string]interface{} func ToMap(obj interface{}) map[string]interface{} { data, err := json.Marshal(obj) @@ -107,3 +118,18 @@ func GetTestDir(t *testing.T) string { } return cwd } + +// CaptureLogEntries captures log entries generated by the logger and return it as string +func CaptureLogEntries(run func()) string { + f := log.StandardLogger().Formatter + log.SetFormatter(&log.TextFormatter{DisableColors: true}) + defer log.SetFormatter(f) + output := bytes.NewBuffer(nil) + log.SetOutput(output) + log.SetLevel(log.DebugLevel) + defer log.SetOutput(os.Stdout) + + run() + + return output.String() +} diff --git a/tools/cmd-docs/main.go b/tools/cmd-docs/main.go index 6b49678a4b73a..aace315302d4b 100644 --- a/tools/cmd-docs/main.go +++ b/tools/cmd-docs/main.go @@ -1,8 +1,11 @@ package main import ( + "fmt" "log" "os" + "path/filepath" + "strings" "github.com/spf13/cobra/doc" @@ -18,27 +21,36 @@ func main() { os.Setenv("HOME", "/home/user") os.Setenv("XDG_CONFIG_HOME", "/home/user/.config") - err := doc.GenMarkdownTree(argocdcli.NewCommand(), "./docs/user-guide/commands") + identity := func(s string) string { return s } + headerPrepender := func(filename string) string { + // The default header looks like `Argocd app get`. The leading capital letter is off-putting. + // This header overrides the default. It's better visually and for search results. + filename = filepath.Base(filename) + filename = filename[:len(filename)-3] // Drop the '.md' + return fmt.Sprintf("# `%s` Command Reference\n\n", strings.ReplaceAll(filename, "_", " ")) + } + + err := doc.GenMarkdownTreeCustom(argocdcli.NewCommand(), "./docs/user-guide/commands", headerPrepender, identity) if err != nil { log.Fatal(err) } - err = doc.GenMarkdownTree(argocdserver.NewCommand(), "./docs/operator-manual/server-commands") + err = doc.GenMarkdownTreeCustom(argocdserver.NewCommand(), "./docs/operator-manual/server-commands", headerPrepender, identity) if err != nil { log.Fatal(err) } - err = doc.GenMarkdownTree(controller.NewCommand(), "./docs/operator-manual/server-commands") + err = doc.GenMarkdownTreeCustom(controller.NewCommand(), "./docs/operator-manual/server-commands", headerPrepender, identity) if err != nil { log.Fatal(err) } - err = doc.GenMarkdownTree(reposerver.NewCommand(), "./docs/operator-manual/server-commands") + err = doc.GenMarkdownTreeCustom(reposerver.NewCommand(), "./docs/operator-manual/server-commands", headerPrepender, identity) if err != nil { log.Fatal(err) } - err = doc.GenMarkdownTree(argocddex.NewCommand(), "./docs/operator-manual/server-commands") + err = doc.GenMarkdownTreeCustom(argocddex.NewCommand(), "./docs/operator-manual/server-commands", headerPrepender, identity) if err != nil { log.Fatal(err) } diff --git a/ui-test/Dockerfile b/ui-test/Dockerfile index a58d05f23fda4..46231bad8d142 100644 --- a/ui-test/Dockerfile +++ b/ui-test/Dockerfile @@ -1,4 +1,4 @@ -FROM node:12.18.4 AS node +FROM docker.io/library/node:21.7.1@sha256:b9ccc4aca32eebf124e0ca0fd573dacffba2b9236987a1d4d2625ce3c162ecc8 as node RUN apt-get update && apt-get install --no-install-recommends -y \ software-properties-common diff --git a/ui-test/osv-scanner.toml b/ui-test/osv-scanner.toml new file mode 100644 index 0000000000000..fe1660cf6d497 --- /dev/null +++ b/ui-test/osv-scanner.toml @@ -0,0 +1,15 @@ +[[IgnoredVulns]] +id = "GHSA-93q8-gq69-wqmw" +reason = "CVE-2021-3807 Code is only run client-side in the swagger-ui endpoint. No risk of server-side DoS." + +[[IgnoredVulns]] +id = "GHSA-36fh-84j7-cv5h" +reason = "Used in testing, does not affect a release" + +[[IgnoredVulns]] +id = "GHSA-f8q6-p94x-37v3" +reason = "Used in testing, does not affect a release" + +[[IgnoredVulns]] +id = "GHSA-qrpm-p2h7-hrv2" +reason = "Used in testing, does not affect a release" \ No newline at end of file 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 dbda283031734..9d7f089c6f4d9 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.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== foreach@^2.0.5: version "2.0.5" @@ -1222,9 +1222,9 @@ selenium-webdriver@^4.0.0-alpha.7: ws "^7.3.1" semver@^5.3.0: - version "5.7.1" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== serialize-javascript@5.0.1: version "5.0.1" @@ -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 82f87fa0a5788..a8d3ff91fa10d 100644 --- a/ui/.nvmrc +++ b/ui/.nvmrc @@ -1 +1 @@ -v12.18.4 +v21.6.1 diff --git a/ui/embed.go b/ui/embed.go index 665621a9c12fd..8f9c2774fbbca 100644 --- a/ui/embed.go +++ b/ui/embed.go @@ -3,5 +3,6 @@ package ui import "embed" // Embedded contains embedded UI resources +// //go:embed dist/app var Embedded embed.FS 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/osv-scanner.toml b/ui/osv-scanner.toml new file mode 100644 index 0000000000000..683f8c5c4b866 --- /dev/null +++ b/ui/osv-scanner.toml @@ -0,0 +1,3 @@ +[[IgnoredVulns]] +id = "GHSA-93q8-gq69-wqmw" +reason = "CVE-2021-3807 Code is only run client-side in the swagger-ui endpoint. No risk of server-side DoS." diff --git a/ui/package.json b/ui/package.json index b5fcdc9808a2b..8eaaaa26dfcfe 100644 --- a/ui/package.json +++ b/ui/package.json @@ -6,26 +6,32 @@ "start": "webpack-dev-server --config ./src/app/webpack.config.js --mode development", "docker": "./scripts/build_docker.sh", "build": "find ./dist -type f -not -name gitkeep -delete && webpack --config ./src/app/webpack.config.js --mode production", - "lint": "tslint -p ./src/app", + "lint": "tsc --noEmit --project ./src/app && tslint -p ./src/app", + "lint:fix": "tslint -p ./src/app --fix", "test": "jest" }, "dependencies": { - "@types/superagent": "^4.1.15", + "@fortawesome/fontawesome-free": "^6.4.0", + "@types/react-virtualized": "^9.21.21", + "@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", "classnames": "^2.2.5", "color": "^3.2.1", "dagre": "^0.8.5", + "date-fns": "^2.30.0", "deepmerge": "^3.2.0", - "foundation-sites": "^6.7.4", + "foundation-sites": "^6.7.5", "git-url-parse": "^13.1.0", + "history": "^4.7.2", "js-yaml": "^3.14.1", "json-merge-patch": "^0.2.3", "lodash-es": "^4.17.21", "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", @@ -34,27 +40,29 @@ "react-dom": "^16.9.3", "react-form": "2.16.3", "react-ga": "^2.7.0", - "react-helmet": "^5.2.0", + "react-helmet": "^6.1.0", "react-hot-loader": "^3.1.3", "react-moment": "^0.9.7", "react-paginate": "^8.1.4", "react-router": "^4.3.1", "react-router-dom": "^4.2.2", "react-svg-piechart": "^2.4.2", + "react-virtualized": "^9.22.3", "redoc": "^2.0.0-rc.64", "rxjs": "^6.6.6", - "superagent": "^7.1.6", + "superagent": "^8.1.2", "timezones-list": "3.0.1", "tsx": "^3.4.0", "unidiff": "^1.0.2", "url": "^0.11.0", - "xterm": "^4.18.0", + "xterm": "^4.19.0", "xterm-addon-fit": "^0.5.0" }, "resolutions": { "@types/react": "^16.9.3", "@types/react-dom": "^16.8.2", - "normalize-url": "4.3.0" + "normalize-url": "4.3.0", + "rxjs": "6.6.7" }, "devDependencies": { "@babel/core": "^7.7.2", @@ -70,20 +78,22 @@ "@types/js-yaml": "^3.11.2", "@types/lodash-es": "^4.17.6", "@types/minimatch": "^3.0.3", + "@types/node": "20.6.3", "@types/prop-types": "^15.7.5", "@types/react": "^16.8.5", "@types/react-autocomplete": "^1.8.4", "@types/react-dom": "^16.9.14", "@types/react-form": "^2.16.0", - "@types/react-helmet": "^5.0.17", + "@types/react-helmet": "^6.1.6", "@types/react-paginate": "^6.2.0", "@types/react-router": "^4.0.27", "@types/react-router-dom": "^4.2.3", "@types/react-test-renderer": "^16.8.3", + "@types/uuid": "^9.0.1", "add": "^2.0.6", "babel-jest": "^26.6.3", "babel-loader": "^8.0.6", - "codecov": "^3.7.2", + "codecov": "^3.8.3", "copy-webpack-plugin": "^6.1.1", "esbuild-loader": "^2.18.0", "html-webpack-plugin": "^5.5.0", @@ -92,7 +102,7 @@ "jest-junit": "^6.4.0", "jest-transform-css": "^2.0.0", "monaco-editor-webpack-plugin": "^7.0.0", - "postcss": "^8.2.13", + "postcss": "^8.4.38", "prettier": "1.19", "raw-loader": "^0.5.1", "react-test-renderer": "16.8.3", @@ -101,15 +111,15 @@ "source-map-loader": "^0.2.3", "style-loader": "^0.20.1", "ts-jest": "^27.1.3", - "ts-node": "^10.7.0", + "ts-node": "10.9.1", "tslint": "^6.1.3", "tslint-config-prettier": "^1.18.0", "tslint-plugin-prettier": "^2.0.1", "tslint-react": "^5.0.0", - "typescript": "^4.0.3", - "webpack": "^5.70.0", + "typescript": "^4.9.5", + "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 b474c86b3ca84..d0a58d3fbdc7f 100644 --- a/ui/src/app/app.tsx +++ b/ui/src/app/app.tsx @@ -9,6 +9,7 @@ import help from './help'; import login from './login'; import settings from './settings'; import {Layout} from './shared/components/layout/layout'; +import {Page} from './shared/components/page/page'; import {VersionPanel} from './shared/components/version-info/version-info-panel'; import {AuthSettingsCtx, Provider} from './shared/context'; import {services} from './shared/services'; @@ -17,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'); @@ -31,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 { @@ -176,7 +179,9 @@ export class App extends React.Component< {extension.title} - Argo CD - + + + ); extendedRoutes[extension.path] = { @@ -214,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-conditions/application-conditions.scss b/ui/src/app/applications/components/application-conditions/application-conditions.scss index 13291efa9421f..d2b6003cddd5f 100644 --- a/ui/src/app/applications/components/application-conditions/application-conditions.scss +++ b/ui/src/app/applications/components/application-conditions/application-conditions.scss @@ -20,5 +20,11 @@ .columns { white-space: normal; } + + .row { + line-height: 2; + padding-top: 15px; + padding-bottom: 15px; + } } } diff --git a/ui/src/app/applications/components/application-conditions/application-conditions.tsx b/ui/src/app/applications/components/application-conditions/application-conditions.tsx index 5c174caaa1425..317b135eeffe4 100644 --- a/ui/src/app/applications/components/application-conditions/application-conditions.tsx +++ b/ui/src/app/applications/components/application-conditions/application-conditions.tsx @@ -16,7 +16,9 @@ export const ApplicationConditions = ({conditions}: {conditions: models.Applicat
    {condition.type}
    -
    {condition.message}
    +
    + {condition.message} +
    diff --git a/ui/src/app/applications/components/application-create-panel/application-create-panel.tsx b/ui/src/app/applications/components/application-create-panel/application-create-panel.tsx index db87258b6bea3..eef8c8ec32103 100644 --- a/ui/src/app/applications/components/application-create-panel/application-create-panel.tsx +++ b/ui/src/app/applications/components/application-create-panel/application-create-panel.tsx @@ -108,15 +108,24 @@ export const ApplicationCreatePanel = (props: { const [explicitPathType, setExplicitPathType] = React.useState<{path: string; type: models.AppSourceType}>(null); const [destFormat, setDestFormat] = React.useState('URL'); const [retry, setRetry] = React.useState(false); + const app = deepMerge(DEFAULT_APP, props.app || {}); + + React.useEffect(() => { + if (app?.spec?.destination?.name && app.spec.destination.name !== '') { + setDestFormat('NAME'); + } else { + setDestFormat('URL'); + } + }, []); function normalizeTypeFields(formApi: FormApi, type: models.AppSourceType) { - const app = formApi.getFormState().values; + const appToNormalize = formApi.getFormState().values; for (const item of appTypes) { if (item.type !== type) { - delete app.spec.source[item.field]; + delete appToNormalize.spec.source[item.field]; } } - formApi.setAllValues(app); + formApi.setAllValues(appToNormalize); } return ( @@ -132,7 +141,6 @@ export const ApplicationCreatePanel = (props: { }> {({projects, clusters, reposInfo}) => { const repos = reposInfo.map(info => info.repo).sort(); - const app = deepMerge(DEFAULT_APP, props.app || {}); const repoInfo = reposInfo.find(info => info.repo === app.spec.source.repoURL); if (repoInfo) { normalizeAppSource(app, repoInfo.type || 'git'); @@ -211,7 +219,10 @@ export const ApplicationCreatePanel = (props: { qeId='application-create-field-project' field='spec.project' component={AutocompleteField} - componentProps={{items: projects}} + componentProps={{ + items: projects, + filterSuggestions: true + }} />
    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 b612c9ed9056c..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'; @@ -32,16 +33,22 @@ export const ApplicationDeploymentHistory = ({
    selectDeployment(index)}>
    - Deployed At: + Deployed At:

    - Time to deploy: + Time to deploy:
    {(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-deployment-history/revision-metadata-rows.tsx b/ui/src/app/applications/components/application-deployment-history/revision-metadata-rows.tsx index 21d7d65133e57..3fa7c62ed1caa 100644 --- a/ui/src/app/applications/components/application-deployment-history/revision-metadata-rows.tsx +++ b/ui/src/app/applications/components/application-deployment-history/revision-metadata-rows.tsx @@ -1,22 +1,46 @@ import {DataLoader} from 'argo-ui'; import * as React from 'react'; import {Timestamp} from '../../../shared/components/timestamp'; -import {ApplicationSource, RevisionMetadata} from '../../../shared/models'; +import {ApplicationSource, RevisionMetadata, ChartDetails} from '../../../shared/models'; import {services} from '../../../shared/services'; export const RevisionMetadataRows = (props: {applicationName: string; applicationNamespace: string; source: ApplicationSource}) => { if (props.source.chart) { return ( -
    -
    -
    Helm Chart
    -
    {props.source.chart}
    -
    -
    -
    Version
    -
    v{props.source.targetRevision}
    -
    -
    + services.applications.revisionChartDetails(input.applicationName, input.applicationNamespace, input.source.targetRevision)}> + {(m: ChartDetails) => ( +
    +
    +
    Helm Chart:
    +
    + {props.source.chart}  + {m.home && ( + { + e.stopPropagation(); + window.open(m.home); + }}> + + + )} +
    +
    + {m.description && ( +
    +
    Description:
    +
    {m.description}
    +
    + )} + {m.maintainers && m.maintainers.length > 0 && ( +
    +
    Maintainers:
    +
    {m.maintainers.join(', ')}
    +
    + )} +
    + )} +
    ); } return ( 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 9f7433d2f7e14..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: 115px; - height: calc(100vh - 2 * 50px - 115px); - @media screen and (max-width: map-get($breakpoints, xlarge)) { - margin-top: 165px; - } + overscroll-behavior-x: none; } &__sliding-panel-pagination-wrap { @@ -48,7 +47,7 @@ $header: 120px; &__refreshing-label { color: $white-color; position: fixed; - top: $header + 100px; + margin-top: -20px; left: 50%; background-color: $argo-color-gray-7; border: 1px solid $argo-color-gray-5; @@ -154,7 +153,7 @@ $header: 120px; } } - @media screen and (max-width: map-get($breakpoints, xlarge)) { + @media screen and (max-width: map-get($breakpoints, xxlarge)) { .page__content-wrapper { min-height: calc(100vh - 3 * 50px); } @@ -211,9 +210,13 @@ $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: fixed; + position: absolute; + + @include themify($themes) { + background: themed('background-2'); + } + a { padding: 5px; @@ -227,7 +230,6 @@ $header: 120px; position: relative; display: inline-block; vertical-align: middle; - font-size: 13px; font-weight: 500; line-height: 1.4; text-align: center; @@ -246,21 +248,27 @@ $header: 120px; &.group-nodes-button-on { color: $argo-color-gray-1; background-color: $argo-color-gray-6; + border: 3px solid $argo-color-teal-4; + font-size: 14px; + outline-style: solid; &:hover { background-color: $argo-color-gray-5; } + } } .separator { - border-right: 1px solid $argo-color-gray-4; + @include themify($themes) { + border-right: 1px solid themed('border'); + } padding-top: 6px; padding-bottom: 6px; } .zoom-value { user-select: none; - margin-top: 3px; + margin-top: 5px; margin-right: 6px; margin-left: 4px; font-size: 14px; @@ -273,75 +281,97 @@ $header: 120px; color: $argo-color-gray-7; } } -} -@media screen and (max-width: map-get($breakpoints, large)) { -.sliding-panel__body { - padding: 4px !important; -} -.sliding-panel--is-middle .sliding-panel__wrapper { - width: 90% !important; -} -.sliding-panel--is-middle .sliding-panel__body { - padding: 18px !important; -} -.sliding-panel__close { - z-index: 2 !important; -} -.top-bar__title { - display: none; -} + @media screen and (max-width: map-get($breakpoints, large)) { + .sliding-panel__body { + padding: 4px !important; + } + .sliding-panel--is-middle .sliding-panel__wrapper { + width: 90% !important; + } + .sliding-panel--is-middle .sliding-panel__body { + padding: 18px !important; + } + .sliding-panel__close { + z-index: 2 !important; + } + .top-bar__title { + display: none; + } -.top-bar__left-side { - white-space: normal !important; -} -.top-bar__left-side > div { - display: block !important; -} -.top-bar__right-side { - justify-content: right !important; -} -.application-status-panel.row { - flex-flow: unset; -} -.application-status-panel__item label { - margin-right: 0; -} -.application-status-panel__item { - padding: 5px 10px; -} + .top-bar__left-side { + white-space: normal !important; + } + .top-bar__left-side > div { + display: block !important; + } + .top-bar__right-side { + justify-content: right !important; + } + .application-status-panel.row { + flex-flow: unset; + } + .application-status-panel__item label { + margin-right: 0; + } + .application-status-panel__item { + padding: 5px 10px; + } -.white-box, .tabs__content { - padding: 4px !important; -} -.white-box__details-row .columns.small-3 { - overflow-wrap: unset !important; - overflow: scroll; -} -.white-box__details-row .columns.small-9{ - padding-left: 4px; -} + .white-box, .tabs__content { + padding: 4px !important; + } + .white-box__details-row .columns.small-3 { + overflow-wrap: unset !important; + overflow: scroll; + } + .white-box__details-row .columns.small-9{ + padding-left: 4px; + } -.resource-details__header h1 { - font-size: 16px; -} -.resource-details__header { - margin-top: 30px; - padding-right: 4px; -} + .resource-details__header h1 { + font-size: 16px; + } + .resource-details__header { + margin-top: 30px; + padding-right: 4px; + } -.tabs__nav a:first-child, .tabs__nav a { - margin-left: 0 !important; -} + .tabs__nav a:first-child, .tabs__nav a { + margin-left: 0 !important; + } -.editable-panel__buttons { - top: unset; -} + .editable-panel__buttons { + top: unset; + } + } } -@media screen and (max-width: map-get($breakpoints, medium)) { -.sb-page-wrapper .top-bar.row { - display: none !important; +.resource-parent-node-info-title { + flex-direction: column; + color: $argo-color-gray-6; + + &__label { + display: flex; + margin-bottom: 0.25em; + flex-shrink: 1; + div:first-child { + margin-right: 10px; + width: 60px; + text-align: right; + } + div:last-child { + font-weight: 500; + width: 100%; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + text-align: left; + + } + } } -} \ No newline at end of file + + + 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 c1c0da6736510..a3e8175591dde 100644 --- a/ui/src/app/applications/components/application-details/application-details.tsx +++ b/ui/src/app/applications/components/application-details/application-details.tsx @@ -25,12 +25,12 @@ import * as AppUtils from '../utils'; import {ApplicationResourceList} from './application-resource-list'; import {Filters, FiltersProps} from './application-resource-filter'; import {getAppDefaultSource, urlPattern, helpTip} from '../utils'; -import {ResourceStatus} from '../../../shared/models'; +import {ChartDetails, ResourceStatus} from '../../../shared/models'; import {ApplicationsDetailsAppDropdown} from './application-details-app-dropdown'; import {useSidebarTarget} from '../../../sidebar/sidebar'; import './application-details.scss'; -import {AppViewExtension, ExtensionComponentProps} 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,8 +89,23 @@ export class ApplicationDetails extends React.Component { extensionsMap[ext.title] = ext; }); - - this.state = {page: 0, groupedResources: [], slidingPanelPage: 0, filteredGraph: [], truncateNameOnRight: false, collapsedNodes: [], extensions, extensionsMap}; + const statusExtensions = services.extensions.getStatusPanelExtensions(); + const statusExtensionsMap: {[key: string]: StatusPanelExtension} = {}; + statusExtensions.forEach(ext => { + statusExtensionsMap[ext.id] = ext; + }); + this.state = { + page: 0, + groupedResources: [], + slidingPanelPage: 0, + filteredGraph: [], + truncateNameOnRight: false, + collapsedNodes: [], + extensions, + extensionsMap, + statusExtensions, + statusExtensionsMap + }; if (typeof this.props.match.params.appnamespace === 'undefined') { this.appNamespace = ''; } else { @@ -134,12 +151,17 @@ export class ApplicationDetails extends React.Component (usrMsg.appName === appName && usrMsg.msgKey === 'groupNodes' ? {...usrMsg, display: true} : usrMsg)); services.viewPreferences.updatePreferences({appDetails: {...pref, groupNodes: !pref.groupNodes}}); } @@ -223,6 +245,7 @@ export class ApplicationDetails extends React.Component usrMsg.appName === application.metadata.name); const resourceNodes = (): any[] => { const statusByKey = new Map(); application.status.resources.forEach(res => statusByKey.set(AppUtils.nodeKey(res), res)); @@ -285,6 +308,17 @@ export class ApplicationDetails extends React.Component { this.setState({filteredGraph: filterGraph}); }; + const setShowCompactNodes = (showCompactView: boolean) => { + services.viewPreferences.updatePreferences({appDetails: {...pref, groupNodes: showCompactView}}); + }; + const updateHelpTipState = (usrHelpTip: models.UserMessages) => { + const existingIndex = pref.userHelpTipMsgs.findIndex(msg => msg.appName === usrHelpTip.appName && msg.msgKey === usrHelpTip.msgKey); + if (existingIndex !== -1) { + pref.userHelpTipMsgs[existingIndex] = usrHelpTip; + } else { + (pref.userHelpTipMsgs || []).push(usrHelpTip); + } + }; const toggleNameDirection = () => { this.setState({truncateNameOnRight: !this.state.truncateNameOnRight}); }; @@ -326,8 +360,17 @@ export class ApplicationDetails extends React.Component +
    ) }}> -
    - 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, this.appChanged, () => - this.getApplicationActionMenu(application, false) - ) - } - showCompactNodes={pref.groupNodes} - tree={tree} - app={application} - showOrphanedResources={pref.orphanedResources} - useNetworkingHierarchy={pref.view === 'network'} - onClearFilter={clearFilter} - onGroupdNodeClick={groupdedNodeIds => openGroupNodeDetails(groupdedNodeIds)} - zoom={pref.zoom} - appContext={this.appContext} - nameDirection={this.state.truncateNameOnRight} - filters={pref.resourceFilter} - setTreeFilterGraph={setFilterGraph} - 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, this.appChanged, () => - this.getApplicationActionMenu(application, false) - ) - } - quickStarts={node => AppUtils.renderResourceButtons(node, application, tree, this.appContext, 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, - 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()}>
    @@ -550,10 +611,11 @@ export class ApplicationDetails extends React.Component this.selectNode(fullName)} resources={data} nodeMenu={node => - AppUtils.renderResourceMenu({...node, root: node}, application, tree, this.appContext, this.appChanged, () => + AppUtils.renderResourceMenu({...node, root: node}, application, tree, this.appContext.apis, this.appChanged, () => this.getApplicationActionMenu(application, false) ) } + tree={tree} /> )} @@ -571,7 +633,7 @@ export class ApplicationDetails extends React.Component AppUtils.showDeploy(null, this.appContext)} + hide={() => AppUtils.showDeploy(null, null, this.appContext.apis)} selectedResource={syncResourceKey} /> -1} onClose={() => this.setRollbackPanelVisible(-1)}> @@ -591,54 +653,107 @@ export class ApplicationDetails extends React.Component} this.setState({revision: null})}> - {this.state.revision && ( - - services.applications.revisionMetadata(application.metadata.name, application.metadata.namespace, this.state.revision) - }> - {metadata => ( -
    -
    -
    -
    SHA:
    -
    - + {this.state.revision && + (source.chart ? ( + + services.applications.revisionChartDetails(input.metadata.name, input.metadata.namespace, this.state.revision) + }> + {(m: ChartDetails) => ( +
    +
    +
    +
    Revision:
    +
    {this.state.revision}
    +
    +
    +
    Helm Chart:
    +
    + {source.chart}  + {m.home && ( + { + e.stopPropagation(); + window.open(m.home); + }}> + + + )} +
    + {m.description && ( +
    +
    Description:
    +
    {m.description}
    +
    + )} + {m.maintainers && m.maintainers.length > 0 && ( +
    +
    Maintainers:
    +
    {m.maintainers.join(', ')}
    +
    + )}
    -
    -
    -
    Date:
    -
    - + )} + + ) : ( + + services.applications.revisionMetadata(application.metadata.name, application.metadata.namespace, this.state.revision) + }> + {metadata => ( +
    +
    +
    +
    SHA:
    +
    + +
    -
    -
    -
    -
    Tags:
    -
    - {((metadata.tags || []).length > 0 && metadata.tags.join(', ')) || 'No tags'} +
    +
    +
    Date:
    +
    + +
    -
    -
    -
    -
    Author:
    -
    {metadata.author}
    +
    +
    +
    Tags:
    +
    + {((metadata.tags || []).length > 0 && metadata.tags.join(', ')) || 'No tags'} +
    +
    -
    -
    -
    -
    Message:
    -
    -
    {renderCommitMessage(metadata.message)}
    +
    +
    +
    Author:
    +
    {metadata.author}
    +
    +
    +
    +
    +
    Message:
    +
    +
    {renderCommitMessage(metadata.message)}
    +
    -
    - )} - + )} + + ))} + + this.setExtensionPanelVisible('')}> + {this.selectedExtension !== '' && activeExtension && activeExtension.flyout && ( + )} @@ -659,19 +774,19 @@ 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 }, { iconClassName: 'fa fa-sync', title: , - action: () => AppUtils.showDeploy('all', this.appContext) + action: () => AppUtils.showDeploy('all', null, this.appContext.apis) }, { iconClassName: 'fa fa-info-circle', @@ -733,7 +848,7 @@ export class ApplicationDetails extends React.Component -1) && + (filterInput.name.length === 0 || this.nodeNameMatchesWildcardFilters(node.name, filterInput.name)) && (filterInput.kind.length === 0 || filterInput.kind.indexOf(node.kind) > -1) && // include if node's root sync matches filter (syncStatuses.length === 0 || hook || (root.status && syncStatuses.indexOf(root.status) > -1)) && @@ -750,6 +865,24 @@ export class ApplicationDetails extends React.Component '^' + this.escapeRegex(pattern) + '$') + // Replace any escaped * with proper regex + .map(pattern => pattern.replace(/\\\*/g, '.*')) + // Join all filterInputs to a single regular expression + .join('|'), + 'gi' + ); + return regularExpression.test(nodeName); + } + + private escapeRegex(input: string): string { + return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + } + private loadAppInfo(name: string, appNamespace: string): Observable<{application: appModels.Application; tree: appModels.ApplicationTree}> { return from(services.applications.get(name, appNamespace)) .pipe( @@ -857,6 +990,10 @@ export class ApplicationDetails extends React.Component any; nodeMenu?: (node: models.ResourceNode) => React.ReactNode; -}) => ( -
    -
    -
    -
    -
    NAME
    -
    GROUP/KIND
    -
    SYNC ORDER
    -
    NAMESPACE
    -
    CREATED AT
    -
    STATUS
    + tree?: models.ApplicationTree; +}) => { + function getResNode(nodes: ResourceNode[], nodeId: string): models.ResourceNode { + for (const node of nodes) { + if (nodeKey(node) === nodeId) { + return node; + } + } + return null; + } + const parentNode = ((resources || []).length > 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}
    +
    -
    - {resources - .sort((first, second) => -createdOrNodeKey(first).localeCompare(createdOrNodeKey(second))) - .map(res => ( -
    onNodeClick(nodeKey(res))}> + ) : ( +
    + ); + }; + return ( +
    + {/* Display only when the view is set to or network */} + {(view === 'tree' || view === 'network') && ( +
    + +
    + )} +
    +
    -
    -
    - -
    -
    {ResourceLabel({kind: res.kind})}
    -
    -
    -
    - {res.name} - {res.kind === 'Application' && ( - - {ctx => ( - - - - +
    +
    NAME
    +
    GROUP/KIND
    +
    SYNC ORDER
    +
    NAMESPACE
    + {(parentNode.kind === 'Rollout' || parentNode.kind === 'Deployment') &&
    REVISION
    } +
    CREATED AT
    +
    STATUS
    +
    +
    + {resources + .sort((first, second) => -createdOrNodeKey(first).localeCompare(createdOrNodeKey(second))) + .map(res => ( +
    onNodeClick(nodeKey(res))}> +
    +
    +
    + +
    +
    {ResourceLabel({kind: res.kind})}
    +
    +
    +
    + {res.name} + {res.kind === 'Application' && ( + + {ctx => ( + + e.stopPropagation()} + title='Open application'> + + + + )} + + )} +
    +
    {[res.group, res.kind].filter(item => !!item).join('/')}
    +
    {res.syncWave || '-'}
    +
    {res.namespace}
    + {res.kind === 'ReplicaSet' && + ((getResNode(tree.nodes, nodeKey(res)) as ResourceNode).info || []) + .filter(tag => !tag.name.includes('Node')) + .slice(0, 4) + .map((tag, i) => { + return ( +
    + {tag?.value?.split(':')[1] || '-'} +
    + ); + })} + +
    + {res.createdAt && ( + + + {res.createdAt} + +  ago   {format(new Date(res.createdAt), 'MM/dd/yy')} )} - - )} -
    -
    {[res.group, res.kind].filter(item => !!item).join('/')}
    -
    {res.syncWave || '-'}
    -
    {res.namespace}
    -
    {res.createdAt}
    -
    - {res.health && ( - - {res.health.status}   - - )} - {res.status && } - {res.hook && } -
    - ( - - )}> - {() => - nodeMenu({ - name: res.name, - version: res.version, - kind: res.kind, - namespace: res.namespace, - group: res.group, - info: null, - uid: '', - resourceVersion: null, - parentRefs: [] - }) - } - +
    +
    + {res.health && ( + + {res.health.status}   + + )} + {res.status && } + {res.hook && } +
    + ( + + )}> + {nodeMenu({ + name: res.name, + version: res.version, + kind: res.kind, + namespace: res.namespace, + group: res.group, + info: null, + uid: '', + resourceVersion: null, + parentRefs: [] + })} + +
    +
    -
    -
    - ))} -
    -); + ))} +
    +
    + ); +}; diff --git a/ui/src/app/applications/components/application-fullscreen-logs/application-fullscreen-logs.tsx b/ui/src/app/applications/components/application-fullscreen-logs/application-fullscreen-logs.tsx index 4314d1e1c6a47..c7e669f46dded 100644 --- a/ui/src/app/applications/components/application-fullscreen-logs/application-fullscreen-logs.tsx +++ b/ui/src/app/applications/components/application-fullscreen-logs/application-fullscreen-logs.tsx @@ -3,12 +3,10 @@ import * as React from 'react'; import Helmet from 'react-helmet'; import {RouteComponentProps} from 'react-router-dom'; import {Query} from '../../../shared/components'; -import {Context} from '../../../shared/context'; import {PodsLogsViewer} from '../pod-logs-viewer/pod-logs-viewer'; import './application-fullscreen-logs.scss'; export const ApplicationFullscreenLogs = (props: RouteComponentProps<{name: string; appnamespace: string; container: string; namespace: string}>) => { - const appContext = React.useContext(Context); return ( {q => { @@ -16,8 +14,6 @@ export const ApplicationFullscreenLogs = (props: RouteComponentProps<{name: stri const name = q.get('name'); const group = q.get('group'); const kind = q.get('kind'); - const page = q.get('page'); - const untilTimes = (q.get('untilTimes') || '').split(',') || []; const title = `${podName || `${group}/${kind}/${name}`}:${props.match.params.container}`; return (
    @@ -32,9 +28,6 @@ export const ApplicationFullscreenLogs = (props: RouteComponentProps<{name: stri kind={kind} name={name} podName={podName} - fullscreen={true} - page={{number: parseInt(page, 10) || 0, untilTimes}} - setPage={pageData => appContext.navigation.goto('.', {page: pageData.number, untilTimes: pageData.untilTimes.join(',')}, {replace: true})} />
    ); diff --git a/ui/src/app/applications/components/application-node-info/application-node-info.scss b/ui/src/app/applications/components/application-node-info/application-node-info.scss index 4edf2235eea22..27ab11d776c17 100644 --- a/ui/src/app/applications/components/application-node-info/application-node-info.scss +++ b/ui/src/app/applications/components/application-node-info/application-node-info.scss @@ -1,4 +1,5 @@ @import 'node_modules/argo-ui/src/styles/config'; +@import 'node_modules/argo-ui/src/styles/theme'; .application-node-info { &__manifest { @@ -6,6 +7,9 @@ .tabs__content { background-color: white; + @include themify($themes){ + background-color: themed('background-2'); + } } &--raw { @@ -37,6 +41,39 @@ label { padding-right: 2em; color: $argo-color-gray-8; + @include themify($themes){ + color: themed('text-2'); + } } } -} + &__err_msg { + padding-right: 2em; + color: $argo-failed-color; + } + &__container { + display: flex; + align-items: center; + flex-direction: row; + line-height: 1.8; + border-bottom: 1px solid rgba(222, 230, 235, 0.7); + + &--name { + width: 15%; + } + &--highlight { + font-style: italic; + } + + &--hint { + text-decoration: underline; + text-decoration-style: dashed; + cursor: pointer; + &:hover { + text-decoration: none; + } + } + &:last-child { + border-bottom: none; + } + } +} \ No newline at end of file diff --git a/ui/src/app/applications/components/application-node-info/application-node-info.tsx b/ui/src/app/applications/components/application-node-info/application-node-info.tsx index 17b7a5d853bff..edd787e0240c1 100644 --- a/ui/src/app/applications/components/application-node-info/application-node-info.tsx +++ b/ui/src/app/applications/components/application-node-info/application-node-info.tsx @@ -1,6 +1,6 @@ import {Checkbox, DataLoader, Tab, Tabs} from 'argo-ui'; +import classNames from 'classnames'; import * as deepMerge from 'deepmerge'; -import * as moment from 'moment'; import * as React from 'react'; import {YamlEditor, ClipboardText} from '../../../shared/components'; @@ -9,9 +9,85 @@ import * as models from '../../../shared/models'; import {services} from '../../../shared/services'; import {ResourceTreeNode} from '../application-resource-tree/application-resource-tree'; import {ApplicationResourcesDiff} from '../application-resources-diff/application-resources-diff'; -import {ComparisonStatusIcon, formatCreationTimestamp, getPodStateReason, HealthStatusIcon} from '../utils'; - +import {ComparisonStatusIcon, formatCreationTimestamp, getPodReadinessGatesState, getPodStateReason, HealthStatusIcon} from '../utils'; import './application-node-info.scss'; +import {ReadinessGatesNotPassedWarning} from './readiness-gates-not-passed-warning'; + +const RenderContainerState = (props: {container: any}) => { + const state = (props.container.state?.waiting && 'waiting') || (props.container.state?.terminated && 'terminated') || (props.container.state?.running && 'running'); + const status = props.container.state.waiting?.reason || props.container.state.terminated?.reason || props.container.state.running?.reason; + const lastState = props.container.lastState?.terminated; + const msg = props.container.state.waiting?.message || props.container.state.terminated?.message || props.container.state.running?.message; + + return ( +
    +
    + {props.container.state?.running && ( + + + + )} + {(props.container.state.terminated && props.container.state.terminated?.exitCode !== 0) || + (lastState && lastState?.exitCode !== 0 && ( + + + + ))} + {props.container.name} +
    +
    + {state && ( + <> + Container is {state} + {status && ' because of '} + + )} + + {status && ( + + {status} + + )} + + {'.'} + {(props.container.state.terminated?.exitCode === 0 || props.container.state.terminated?.exitCode) && ( + <> + {' '} + It exited with exit code {props.container.state.terminated.exitCode}. + + )} + <> + {' '} + It is {props.container?.started ? 'started' : 'not started'} + {status === 'Completed' ? '.' : props.container?.ready ? ' and ready.' : ' and not ready.'} + +
    + {lastState && ( + <> + <> + The container last terminated with exit code {lastState?.exitCode} + + {lastState?.reason && ' because of '} + + {lastState?.reason && ( + + {lastState?.reason} + + )} + + {'.'} + + )} +
    +
    + ); +}; export const ApplicationNodeInfo = (props: { application: models.Application; @@ -45,13 +121,26 @@ export const ApplicationNodeInfo = (props: { ) }); } + if (props.live) { if (props.node.kind === 'Pod') { - const {reason, message} = getPodStateReason(props.live); + const {reason, message, netContainerStatuses} = getPodStateReason(props.live); attributes.push({title: 'STATE', value: reason}); if (message) { attributes.push({title: 'STATE DETAILS', value: message}); } + if (netContainerStatuses.length > 0) { + attributes.push({ + title: 'CONTAINER STATE', + value: ( +
    + {netContainerStatuses.map((container, i) => { + return ; + })} +
    + ) + }); + } } else if (props.node.kind === 'Service') { attributes.push({title: 'TYPE', value: props.live.spec.type}); let hostNames = ''; @@ -61,7 +150,7 @@ export const ApplicationNodeInfo = (props: { } attributes.push({title: 'HOSTNAMES', value: hostNames}); } else if (props.node.kind === 'ReplicaSet') { - attributes.push({title: 'REPLICAS', value: `${props.live.spec?.replicas || 0}/${props.live.status?.readyReplicas || 0}/${props.live.spec?.replicas || 0}`}); + attributes.push({title: 'REPLICAS', value: `${props.live.spec?.replicas || 0}/${props.live.status?.readyReplicas || 0}/${props.live.status?.replicas || 0}`}); } } @@ -102,7 +191,7 @@ export const ApplicationNodeInfo = (props: { } as any); } } - + let showLiveState = true; if (props.links) { attributes.push({ title: 'LINKS', @@ -118,35 +207,62 @@ export const ApplicationNodeInfo = (props: { services.viewPreferences.getPreferences()}> {pref => { const live = deepMerge(props.live, {}) as any; + if (Object.keys(live).length === 0) { + showLiveState = false; + } + if (live?.metadata?.managedFields && pref.appDetails.hideManagedFields) { delete live.metadata.managedFields; } return ( - <> -
    - - services.viewPreferences.updatePreferences({ - appDetails: { - ...pref.appDetails, - hideManagedFields: !pref.appDetails.hideManagedFields + + {showLiveState ? ( + +
    + + services.viewPreferences.updatePreferences({ + appDetails: { + ...pref.appDetails, + hideManagedFields: !pref.appDetails.hideManagedFields + } + }) } - }) - } - /> - -
    - - services.applications.patchResource(props.application.metadata.name, props.application.metadata.namespace, props.node, patch, patchType) - } - /> - + /> + +
    + + services.applications.patchResource( + props.application.metadata.name, + props.application.metadata.namespace, + props.node, + patch, + patchType + ) + } + /> + + ) : ( +
    + Resource not found in cluster:{' '} + {`${props?.controlled?.state?.targetState?.apiVersion}/${props?.controlled?.state?.targetState?.kind}:${props.node.name}`} +
    + {props?.controlled?.state?.normalizedLiveState?.apiVersion && ( + + Please update your resource specification to use the latest Kubernetes API resources supported by the target cluster. The + recommended syntax is{' '} + {`${props.controlled.state.normalizedLiveState.apiVersion}/${props?.controlled.state.normalizedLiveState?.kind}:${props.node.name}`} + + )} +
    + )} + ); }}
    @@ -167,8 +283,25 @@ export const ApplicationNodeInfo = (props: { }); } + const readinessGatesState = React.useMemo(() => { + // If containers are not ready then readiness gate status is not important. + if (!props.live?.status?.containerStatuses?.length) { + return null; + } + if (props.live?.status?.containerStatuses?.some((containerStatus: {ready: boolean}) => !containerStatus.ready)) { + return null; + } + + if (props.live && props.node?.kind === 'Pod') { + return getPodReadinessGatesState(props.live); + } + + return null; + }, [props.live, props.node]); + return (
    + {Boolean(readinessGatesState) && }
    {attributes.map(attr => ( diff --git a/ui/src/app/applications/components/application-node-info/readiness-gates-not-passed-warning.scss b/ui/src/app/applications/components/application-node-info/readiness-gates-not-passed-warning.scss new file mode 100644 index 0000000000000..7887918671396 --- /dev/null +++ b/ui/src/app/applications/components/application-node-info/readiness-gates-not-passed-warning.scss @@ -0,0 +1,12 @@ +@import 'node_modules/argo-ui/src/styles/config'; + +.white-box { + &__readiness-gates-alert { + padding: 20px; + border-left: 6px solid $argo-status-warning-color !important; + + ul { + margin-bottom: 0; + } + } +} diff --git a/ui/src/app/applications/components/application-node-info/readiness-gates-not-passed-warning.tsx b/ui/src/app/applications/components/application-node-info/readiness-gates-not-passed-warning.tsx new file mode 100644 index 0000000000000..31af11b1d0349 --- /dev/null +++ b/ui/src/app/applications/components/application-node-info/readiness-gates-not-passed-warning.tsx @@ -0,0 +1,44 @@ +import * as React from 'react'; +import {selectPostfix} from '../utils'; + +import './readiness-gates-not-passed-warning.scss'; + +export interface ReadinessGatesNotPassedWarningProps { + readinessGatesState: { + nonExistingConditions: string[]; + notPassedConditions: string[]; + }; +} + +export const ReadinessGatesNotPassedWarning = ({readinessGatesState}: ReadinessGatesNotPassedWarningProps) => { + if (readinessGatesState.notPassedConditions.length > 0 || readinessGatesState.nonExistingConditions.length > 0) { + return ( +
    +
    Readiness Gates Not Passing:
    +
      + {readinessGatesState.notPassedConditions.length > 0 && ( +
    • + The status of pod readiness gate{selectPostfix(readinessGatesState.notPassedConditions, '', 's')}{' '} + {readinessGatesState.notPassedConditions + .map(t => `"${t}"`) + .join(', ') + .trim()}{' '} + {selectPostfix(readinessGatesState.notPassedConditions, 'is', 'are')} False. +
    • + )} + {readinessGatesState.nonExistingConditions.length > 0 && ( +
    • + Corresponding condition{selectPostfix(readinessGatesState.nonExistingConditions, '', 's')} of pod readiness gate{' '} + {readinessGatesState.nonExistingConditions + .map(t => `"${t}"`) + .join(', ') + .trim()}{' '} + do{selectPostfix(readinessGatesState.nonExistingConditions, 'es', '')} not exist. +
    • + )} +
    +
    + ); + } + return null; +}; diff --git a/ui/src/app/applications/components/application-parameters/application-parameters.tsx b/ui/src/app/applications/components/application-parameters/application-parameters.tsx index 330e6f0362c59..38a6d151a90c2 100644 --- a/ui/src/app/applications/components/application-parameters/application-parameters.tsx +++ b/ui/src/app/applications/components/application-parameters/application-parameters.tsx @@ -1,16 +1,30 @@ import {AutocompleteField, DataLoader, FormField, FormSelect, getNestedField} from 'argo-ui'; import * as React from 'react'; import {FieldApi, FormApi, FormField as ReactFormField, Text, TextArea} from 'react-form'; - -import {ArrayInputField, CheckboxField, EditablePanel, EditablePanelItem, Expandable, TagsInputField} from '../../../shared/components'; +import {cloneDeep} from 'lodash-es'; +import { + ArrayInputField, + ArrayValueField, + CheckboxField, + EditablePanel, + EditablePanelItem, + Expandable, + MapValueField, + NameValueEditor, + StringValueField, + NameValue, + TagsInputField, + ValueEditor +} from '../../../shared/components'; import * as models from '../../../shared/models'; -import {ApplicationSourceDirectory, AuthSettings} from '../../../shared/models'; +import {ApplicationSourceDirectory, Plugin} from '../../../shared/models'; import {services} from '../../../shared/services'; import {ImageTagFieldEditor} from './kustomize'; import * as kustomize from './kustomize-image'; import {VarsInputField} from './vars-input-field'; import {concatMaps} from '../../../shared/utils'; import {getAppDefaultSource} from '../utils'; +import * as jsYaml from 'js-yaml'; const TextWithMetadataField = ReactFormField((props: {metadata: {value: string}; fieldApi: FieldApi; className: string}) => { const { @@ -112,11 +126,14 @@ export const ApplicationParameters = (props: { save?: (application: models.Application, query: {validate?: boolean}) => Promise; noReadonlyMode?: boolean; }) => { - const app = props.application; + const app = cloneDeep(props.application); const source = getAppDefaultSource(app); const [removedOverrides, setRemovedOverrides] = React.useState(new Array()); let attributes: EditablePanelItem[] = []; + const isValuesObject = source?.helm?.valuesObject; + const helmValues = isValuesObject ? jsYaml.safeDump(source.helm.valuesObject) : source?.helm?.values; + const [appParamsDeletedState, setAppParamsDeletedState] = React.useState([]); if (props.details.type === 'Kustomize' && props.details.kustomize) { attributes.push({ @@ -145,6 +162,12 @@ export const ApplicationParameters = (props: { edit: (formApi: FormApi) => }); + attributes.push({ + title: 'NAMESPACE', + view: app.spec.source.kustomize && app.spec.source.kustomize.namespace, + edit: (formApi: FormApi) => + }); + const srcImages = ((props.details && props.details.kustomize && props.details.kustomize.images) || []).map(val => kustomize.parse(val)); const images = ((source.kustomize && source.kustomize.images) || []).map(val => kustomize.parse(val)); @@ -196,16 +219,23 @@ export const ApplicationParameters = (props: { title: 'VALUES', view: source.helm && ( -
    {source.helm.values}
    +
    {helmValues}
    ), - edit: (formApi: FormApi) => ( -
    -
    -                        
    -                    
    -
    - ) + edit: (formApi: FormApi) => { + // In case source.helm.valuesObject is set, set source.helm.values to its value + if (source.helm) { + source.helm.values = helmValues; + } + + return ( +
    +
    +                            
    +                        
    +
    + ); + } }); const paramsByName = new Map(); (props.details.helm.parameters || []).forEach(param => paramsByName.set(param.name, param)); @@ -256,50 +286,170 @@ export const ApplicationParameters = (props: { } else if (props.details.type === 'Plugin') { attributes.push({ title: 'NAME', - view: source.plugin && source.plugin.name, + view:
    {ValueEditor(app.spec.source?.plugin?.name, null)}
    , edit: (formApi: FormApi) => ( - services.authService.settings()}> - {(settings: AuthSettings) => ( - p.name)}} /> + services.authService.plugins()}> + {(plugins: Plugin[]) => ( + p.name)}} /> )} ) }); attributes.push({ title: 'ENV', - view: source.plugin && (source.plugin.env || []).map(i => `${i.name}='${i.value}'`).join(' '), + view: ( +
    + {(app.spec.source?.plugin?.env || []).map(val => ( + + {NameValueEditor(val, null)} + + ))} +
    + ), edit: (formApi: FormApi) => }); - if (props.details.plugin.parametersAnnouncement) { + const parametersSet = new Set(); + if (props.details?.plugin?.parametersAnnouncement) { for (const announcement of props.details.plugin.parametersAnnouncement) { - const liveParam = app.spec.source.plugin.parameters?.find(param => param.name === announcement.name); - if (announcement.collectionType === undefined || announcement.collectionType === '' || announcement.collectionType === 'string') { - attributes.push({ - title: announcement.title ?? announcement.name, - view: liveParam?.string || announcement.string, - edit: () => liveParam?.string || announcement.string - }); - } else if (announcement.collectionType === 'array') { - attributes.push({ - title: announcement.title ?? announcement.name, - view: (liveParam?.array || announcement.array || []).join(' '), - edit: () => (liveParam?.array || announcement.array || []).join(' ') - }); - } else if (announcement.collectionType === 'map') { - const entries = concatMaps(announcement.map, liveParam?.map).entries(); - attributes.push({ - title: announcement.title ?? announcement.name, - view: Array.from(entries) - .map(([key, value]) => `${key}='${value}'`) - .join(' '), - edit: () => - Array.from(entries) - .map(([key, value]) => `${key}='${value}'`) - .join(' ') - }); - } + parametersSet.add(announcement.name); } } + if (app.spec.source?.plugin?.parameters) { + for (const appParameter of app.spec.source.plugin.parameters) { + parametersSet.add(appParameter.name); + } + } + + for (const key of appParamsDeletedState) { + parametersSet.delete(key); + } + parametersSet.forEach(name => { + const announcement = props.details.plugin.parametersAnnouncement?.find(param => param.name === name); + const liveParam = app.spec.source?.plugin?.parameters?.find(param => param.name === name); + const pluginIcon = + announcement && liveParam ? 'This parameter has been provided by plugin, but is overridden in application manifest.' : 'This parameter is provided by the plugin.'; + const isPluginPar = !!announcement; + if ((announcement?.collectionType === undefined && liveParam?.map) || announcement?.collectionType === 'map') { + let liveParamMap; + if (liveParam) { + liveParamMap = liveParam.map ?? new Map(); + } + const map = concatMaps(liveParamMap ?? announcement?.map, new Map()); + const entries = map.entries(); + const items = new Array(); + Array.from(entries).forEach(([key, value]) => items.push({name: key, value: `${value}`})); + attributes.push({ + title: announcement?.title ?? announcement?.name ?? name, + customTitle: ( + + {isPluginPar && } + {announcement?.title ?? announcement?.name ?? name} + + ), + view: ( +
    + {items.length === 0 && -- NO ITEMS --} + {items.map(val => ( + + {NameValueEditor(val)} + + ))} +
    + ), + edit: (formApi: FormApi) => ( + + ) + }); + } else if ((announcement?.collectionType === undefined && liveParam?.array) || announcement?.collectionType === 'array') { + let liveParamArray; + if (liveParam) { + liveParamArray = liveParam?.array ?? []; + } + attributes.push({ + title: announcement?.title ?? announcement?.name ?? name, + customTitle: ( + + {isPluginPar && } + {announcement?.title ?? announcement?.name ?? name} + + ), + view: ( +
    + {(liveParamArray ?? announcement?.array ?? []).length === 0 && -- NO ITEMS --} + {(liveParamArray ?? announcement?.array ?? []).map((val, index) => ( + + {ValueEditor(val, null)} + + ))} +
    + ), + edit: (formApi: FormApi) => ( + + ) + }); + } else if ( + (announcement?.collectionType === undefined && liveParam?.string) || + announcement?.collectionType === '' || + announcement?.collectionType === 'string' || + announcement?.collectionType === undefined + ) { + let liveParamString; + if (liveParam) { + liveParamString = liveParam?.string ?? ''; + } + attributes.push({ + title: announcement?.title ?? announcement?.name ?? name, + customTitle: ( + + {isPluginPar && } + {announcement?.title ?? announcement?.name ?? name} + + ), + view: ( +
    + {ValueEditor(liveParamString ?? announcement?.string, null)} +
    + ), + edit: (formApi: FormApi) => ( + + ) + }); + } + }); } else if (props.details.type === 'Directory') { const directory = source.directory || ({} as ApplicationSourceDirectory); attributes.push({ @@ -345,6 +495,7 @@ export const ApplicationParameters = (props: { props.save && (async (input: models.Application) => { const src = getAppDefaultSource(input); + function isDefined(item: any) { return item !== null && item !== undefined; } @@ -358,11 +509,33 @@ export const ApplicationParameters = (props: { if (src.kustomize && src.kustomize.images) { src.kustomize.images = src.kustomize.images.filter(isDefinedWithVersion); } + + let params = input.spec?.source?.plugin?.parameters; + if (params) { + for (const param of params) { + if (param.map && param.array) { + // @ts-ignore + param.map = param.array.reduce((acc, {name, value}) => { + // @ts-ignore + acc[name] = value; + return acc; + }, {}); + delete param.array; + } + } + + params = params.filter(param => !appParamsDeletedState.includes(param.name)); + input.spec.source.plugin.parameters = params; + } + if (input.spec.source.helm && input.spec.source.helm.valuesObject) { + input.spec.source.helm.valuesObject = jsYaml.safeLoad(input.spec.source.helm.values); // Deserialize json + input.spec.source.helm.values = ''; + } await props.save(input, {}); setRemovedOverrides(new Array()); }) } - values={app} + values={((props.details.plugin || app?.spec?.source?.plugin) && cloneDeep(app)) || app} validate={updatedApp => { const errors = {} as any; @@ -371,11 +544,23 @@ export const ApplicationParameters = (props: { errors[fieldPath] = invalid.length > 0 ? 'All fields must have name' : null; } + if (updatedApp.spec.source.helm && updatedApp.spec.source.helm.values) { + const parsedValues = jsYaml.safeLoad(updatedApp.spec.source.helm.values); + errors['spec.source.helm.values'] = typeof parsedValues === 'object' ? null : 'Values must be a map'; + } + return errors; }} + onModeSwitch={ + props.details.plugin && + (() => { + setAppParamsDeletedState([]); + }) + } title={props.details.type.toLocaleUpperCase()} items={attributes} noReadonlyMode={props.noReadonlyMode} + hasMultipleSources={app.spec.sources && app.spec.sources.length > 0} /> ); }; diff --git a/ui/src/app/applications/components/application-pod-view/pod-tooltip.tsx b/ui/src/app/applications/components/application-pod-view/pod-tooltip.tsx new file mode 100644 index 0000000000000..51303a1334b56 --- /dev/null +++ b/ui/src/app/applications/components/application-pod-view/pod-tooltip.tsx @@ -0,0 +1,51 @@ +import * as React from 'react'; +import Moment from 'react-moment'; +import {Pod} from '../../../shared/models'; +import {isYoungerThanXMinutes} from '../utils'; + +export const PodTooltip = (props: {pod: Pod}) => { + const pod = props.pod; + + return ( +
    +
    +
    {pod.metadata.name}
    +
    +
    +
    Health:
    +
    {pod.health}
    +
    + {(pod.info || []) + .filter(i => i.name !== 'Node') + .map(i => ( +
    +
    + {i.name}: +
    +
    {i.value}
    +
    + ))} + {pod.createdAt && ( +
    +
    + Created: +
    +
    + + {pod.createdAt} + + ago +
    + {isYoungerThanXMinutes(pod, 30) && ( +
    + +   + pod age less than 30min + +
    + )} +
    + )} +
    + ); +}; diff --git a/ui/src/app/applications/components/application-pod-view/pod-view.scss b/ui/src/app/applications/components/application-pod-view/pod-view.scss index 24b2b79a9f33f..372bf1b0fa6ca 100644 --- a/ui/src/app/applications/components/application-pod-view/pod-view.scss +++ b/ui/src/app/applications/components/application-pod-view/pod-view.scss @@ -246,3 +246,7 @@ $pod-age-icon-clr: #ffce25; } } } + +.tippy-content { + text-align: left; +} diff --git a/ui/src/app/applications/components/application-pod-view/pod-view.tsx b/ui/src/app/applications/components/application-pod-view/pod-view.tsx index 5d9493872c4a6..2c1bb54770abf 100644 --- a/ui/src/app/applications/components/application-pod-view/pod-view.tsx +++ b/ui/src/app/applications/components/application-pod-view/pod-view.tsx @@ -14,6 +14,7 @@ import {ResourceLabel} from '../resource-label'; import {ComparisonStatusIcon, isYoungerThanXMinutes, HealthStatusIcon, nodeKey, PodHealthIcon, deletePodAction} from '../utils'; import './pod-view.scss'; +import {PodTooltip} from './pod-tooltip'; interface PodViewProps { tree: ApplicationTree; @@ -163,29 +164,7 @@ export class PodView extends React.Component { key={pod.uid} anchor={() => ( - {pod.metadata.name} -
    Health: {pod.health}
    - {pod.createdAt && ( - - Created: - - {pod.createdAt} - - ago ({{pod.createdAt}}) -
    - {isYoungerThanXMinutes(pod, 30) && ( - -   - pod age less than 30min - - )} -
    -
    - )} -
    - } + content={} popperOptions={{ modifiers: { preventOverflow: { @@ -246,7 +225,12 @@ export class PodView extends React.Component { ), action: () => { - deletePodAction(pod, this.appContext, this.props.app.metadata.name); + deletePodAction( + pod, + this.appContext, + this.props.app.metadata.name, + this.props.app.metadata.namespace + ); } } ]} 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 74ad1e53a79fc..9f3879d617732 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 @@ -71,7 +71,7 @@ padding-right: 1em; margin: 10px; box-shadow: 1px 1px 1px $argo-color-gray-4; - @include themify($themes) { + @include themify($themes) { background-color: themed('background-2'); color: themed('text-2'); } @@ -79,10 +79,19 @@ border: 1px solid transparent; cursor: pointer; + .theme-dark & { + box-shadow: 1px 1px 1px $argo-color-gray-7; + } + .icon { font-size: 2em; } + .icon-background + { + color: $argo-color-gray-4; + } + .fa-filter { margin-left: 8px; padding: 2px; @@ -94,7 +103,7 @@ &--orphaned { @include themify($themes) { - background-color: themed('light-argo-gray-2'); + background-color: themed('light-argo-gray-2') !important; } } @@ -110,13 +119,17 @@ font-size: 0.5em; padding: 2px; box-shadow: 1px 1px 1px $argo-color-gray-4; - @include themify($themes) { + @include themify($themes) { background-color: themed('background-2'); } margin-top: 9px; margin-left: 215px; + + .theme-dark & { + box-shadow: 1px 1px 1px $argo-color-gray-7; + } } - + &--podgroup--expansion { position: absolute; flex-shrink: 0px; @@ -126,10 +139,14 @@ 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 { - @include themify($themes) { + @include themify($themes) { background-color: themed('pod-cyan') !important; } } @@ -146,7 +163,7 @@ padding: $padding; transition: all 1s linear; position: absolute; - + &__pod-group { $pod-container-width: $pods-per-row * ($pod-size + (2 * $gutter)) + 4 * $gutter; $pod-container-height: $pods-per-column * ($pod-size + (2 * $gutter)) + 4 * $gutter; @@ -168,6 +185,7 @@ width: 100%; background-color: $argo-color-gray-3; border-radius: 3px; + align-items: center; padding: $gutter * 2; margin-right: -1 * $gutter; margin-bottom: -1 * $gutter; @@ -235,7 +253,7 @@ } &__stat-tooltip { text-align: left; - + i { display: inline-block; height: 1em; @@ -243,15 +261,15 @@ border-radius: 5px; } } - + &__stat-icon-app { background-color: $argo-color-teal-7; } - + &__stat-icon-neighbors { background-color: $argo-color-gray-6; } - + &__stat { &__bar { background-color: $argo-color-gray-4; @@ -262,22 +280,22 @@ margin: 0 $gutter * 2; overflow: hidden; cursor: pointer; - + &--fill { position: absolute; background-color: $argo-color-teal-7; width: 100%; bottom: 0; } - + &--neighbors { background-color: $argo-color-gray-6; } - + &:hover > &--fill { background-color: $argo-color-teal-8; } - + &:hover &--neighbors { background-color: $argo-color-gray-7; } @@ -338,8 +356,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; @@ -365,6 +387,7 @@ margin-right: 1px; } + &__node-kind { font-size: 0.7em; color: $argo-color-gray-6; @@ -398,5 +421,11 @@ &__direction-right { direction: rtl; } - + &__direction-center-left { + overflow: hidden; + padding-top: 15px; + padding-left: 15px; + + } + } 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 1bd6b42df814a..06ba5e331e041 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 @@ -3,6 +3,7 @@ import * as classNames from 'classnames'; import * as dagre from 'dagre'; import * as React from 'react'; import Moment from 'react-moment'; +import * as moment from 'moment'; import * as models from '../../../shared/models'; @@ -21,12 +22,13 @@ import { isYoungerThanXMinutes, NodeId, nodeKey, - PodHealthIcon + PodHealthIcon, + getUsrMsgKeyToDisplay } from '../utils'; import {NodeUpdateAnimation} from './node-update-animation'; import {PodGroup} from '../application-pod-view/pod-view'; -import {ArrowConnector} from './arrow-connector'; import './application-resource-tree.scss'; +import {ArrowConnector} from './arrow-connector'; function treeNodeKey(node: NodeId & {uid?: string}) { return node.uid || nodeKey(node); @@ -58,7 +60,11 @@ export interface ApplicationResourceTreeProps { appContext?: AppContext; showOrphanedResources: boolean; showCompactNodes: boolean; + userMsgs: models.UserMessages[]; + updateUsrHelpTipMsgs: (userMsgs: models.UserMessages) => void; + setShowCompactNodes: (showCompactNodes: boolean) => void; zoom: number; + podGroupCount: number; filters?: string[]; setTreeFilterGraph?: (filterGraph: any[]) => void; nameDirection: boolean; @@ -87,7 +93,6 @@ const NODE_TYPES = { groupedNodes: 'grouped_nodes', podGroup: 'pod_group' }; - // generate lots of colors with different darkness const TRAFFIC_COLORS = [0, 0.25, 0.4, 0.6] .map(darken => @@ -109,7 +114,7 @@ function getGraphSize(nodes: dagre.Node[]): {width: number; height: number} { return {width, height}; } -function groupNodes(nodes: any[], graph: dagre.graphlib.Graph) { +function groupNodes(nodes: ResourceTreeNode[], graph: dagre.graphlib.Graph) { function getNodeGroupingInfo(nodeId: string) { const node = graph.node(nodeId); return { @@ -173,22 +178,34 @@ function groupNodes(nodes: any[], graph: dagre.graphlib.Graph) { groupedNodesArr.forEach((obj: {kind: string; nodeIds: string[]; parentIds: dagre.Node[]}) => { const {nodeIds, kind, parentIds} = obj; const groupedNodeIds: string[] = []; + const podGroupIds: string[] = []; nodeIds.forEach((nodeId: string) => { const index = nodes.findIndex(node => nodeId === node.uid || nodeId === nodeKey(node)); - if (index > -1) { + const graphNode = graph.node(nodeId); + if (!graphNode?.podGroup && index > -1) { groupedNodeIds.push(nodeId); + } else { + podGroupIds.push(nodeId); } - graph.removeNode(nodeId); - }); - graph.setNode(`${parentIds[0].toString()}/child/${kind}`, { - kind, - groupedNodeIds, - height: NODE_HEIGHT, - width: NODE_WIDTH, - count: nodeIds.length, - type: NODE_TYPES.groupedNodes }); - graph.setEdge(parentIds[0].toString(), `${parentIds[0].toString()}/child/${kind}`); + const reducedNodeIds = nodeIds.reduce((acc, aNodeId) => { + if (podGroupIds.findIndex(i => i === aNodeId) < 0) { + acc.push(aNodeId); + } + return acc; + }, []); + if (groupedNodeIds.length > 1) { + groupedNodeIds.forEach(n => graph.removeNode(n)); + graph.setNode(`${parentIds[0].toString()}/child/${kind}`, { + kind, + groupedNodeIds, + height: NODE_HEIGHT, + width: NODE_WIDTH, + count: reducedNodeIds.length, + type: NODE_TYPES.groupedNodes + }); + graph.setEdge(parentIds[0].toString(), `${parentIds[0].toString()}/child/${kind}`); + } }); } } @@ -216,6 +233,14 @@ export function compareNodes(first: ResourceTreeNode, second: ResourceTreeNode) } return value.replace(/^Rev:/, ''); } + if (first.kind === 'ReplicaSet') { + return ( + orphanedToInt(first.orphaned) - orphanedToInt(second.orphaned) || + compareRevision(getRevision(second), getRevision(first)) || + nodeKey(first).localeCompare(nodeKey(second)) || + 0 + ); + } return ( orphanedToInt(first.orphaned) - orphanedToInt(second.orphaned) || nodeKey(first).localeCompare(nodeKey(second)) || @@ -271,10 +296,22 @@ function renderGroupedNodes(props: ApplicationResourceTreeProps, node: {count: n
    {ResourceLabel({kind: node.kind})}
    -
    - props.onGroupdNodeClick && props.onGroupdNodeClick(node.groupedNodeIds)}> - click to show details of {node.count} collapsed {node.kind} - +
    props.onGroupdNodeClick && props.onGroupdNodeClick(node.groupedNodeIds)} + title={`Click to see details of ${node.count} collapsed ${node.kind} and doesn't contains any active pods`}> + {node.count} {node.kind}s + + {node.kind === 'ReplicaSet' ? ( + + ) : ( + + )} +
    {indicators.map(i => ( @@ -387,21 +424,47 @@ function renderPodGroup(props: ApplicationResourceTreeProps, id: string, node: R const margin = 8; let topExtra = 0; const podGroup = node.podGroup; + const podGroupHealthy = []; + const podGroupDegraded = []; + const podGroupInProgress = []; + + for (const pod of podGroup?.pods || []) { + switch (pod.health) { + case 'Healthy': + podGroupHealthy.push(pod); + break; + case 'Degraded': + podGroupDegraded.push(pod); + break; + case 'Progressing': + podGroupInProgress.push(pod); + } + } + + const showPodGroupByStatus = props.tree.nodes.filter((rNode: ResourceTreeNode) => rNode.kind === 'Pod').length >= props.podGroupCount; + const numberOfRows = showPodGroupByStatus + ? [podGroupHealthy, podGroupDegraded, podGroupInProgress].reduce((total, podGroupByStatus) => total + (podGroupByStatus.filter(pod => pod).length > 0 ? 1 : 0), 0) + : Math.ceil(podGroup?.pods.length / 8); + if (podGroup) { - const numberOfRows = Math.ceil(podGroup.pods.length / 8); topExtra = margin + (POD_NODE_HEIGHT / 2 + 30 * numberOfRows) / 2; } + return (
    props.onNodeClick && props.onNodeClick(fullName)} className={classNames('application-resource-tree__node', { 'active': fullName === props.selectedNodeFullName, 'application-resource-tree__node--orphaned': node.orphaned })} title={describeNode(node)} - style={{left: node.x, top: node.y - topExtra, width: node.width, height: node.height}}> + style={{ + left: node.x, + top: node.y - topExtra, + width: node.width, + height: showPodGroupByStatus ? POD_NODE_HEIGHT + 20 * numberOfRows : node.height + }}> -
    +
    props.onNodeClick && props.onNodeClick(fullName)} className={`application-resource-tree__node__top-part`}>
    + })} + onClick={() => props.onGroupdNodeClick && props.onGroupdNodeClick(node.groupedNodeIds)}> {node.name} 4 && ( ( -
    - {i.name}: {i.value} -
    - ))} + content={ + <> + {(node.info || []).map(i => ( +
    + {i.name}: {i.value} +
    + ))} + + } key={node.uid}> More @@ -482,6 +550,7 @@ function renderPodGroup(props: ApplicationResourceTreeProps, id: string, node: R {props.nodeMenu && (
    (
    - {podGroup && ( -
    -
    -
    - {podGroup.pods.map(pod => ( - ( - - {pod.metadata.name} -
    Health: {pod.health}
    - {pod.createdAt && ( - - Created: - - {pod.createdAt} - - ago ({{pod.createdAt}}) - - )} -
    - } - popperOptions={{ - modifiers: { - preventOverflow: { - enabled: true - }, - hide: { - enabled: false - }, - flip: { - enabled: false - } - } - }} - key={pod.metadata.name}> -
    - {isYoungerThanXMinutes(pod, 30) && ( - - )} -
    - -
    -
    - - )} - items={[ - { - title: ( - - Info - - ), - action: () => props.onNodeClick(pod.fullName) - }, - { - title: ( - - Logs - - ), - action: () => { - props.appContext.apis.navigation.goto('.', {node: pod.fullName, tab: 'logs'}, {replace: true}); - } - }, - { - title: ( - - Delete - - ), - action: () => { - deletePodAction(pod, props.appContext, props.app.metadata.name, props.app.metadata.namespace); - } - } - ]} - /> - ))} + {[podGroupHealthy, podGroupDegraded, podGroupInProgress].map((pods, index) => { + if (pods.length > 0) { + return ( +
    + {renderPodGroupByStatus(props, node, pods, showPodGroupByStatus)}
    -
    PODS
    -
    -
    - )} + ); + } + })}
    ); } +function renderPodGroupByStatus(props: ApplicationResourceTreeProps, node: any, pods: models.Pod[], showPodGroupByStatus: boolean) { + return ( +
    + {pods.length !== 0 && showPodGroupByStatus ? ( + +
    + +
    + + +
    + ) : ( + pods.map(pod => ( + ( + + {pod.metadata.name} +
    Health: {pod.health}
    + {pod.createdAt && ( + + Created: + + {pod.createdAt} + + ago ({{pod.createdAt}}) + + )} +
    + } + popperOptions={{ + modifiers: { + preventOverflow: { + enabled: true + }, + hide: { + enabled: false + }, + flip: { + enabled: false + } + } + }} + key={pod.metadata.name}> +
    + {isYoungerThanXMinutes(pod, 30) && ( + + )} +
    + +
    +
    + + )} + items={[ + { + title: ( + + Info + + ), + action: () => props.onNodeClick(pod.fullName) + }, + { + title: ( + + Logs + + ), + action: () => { + props.appContext.apis.navigation.goto('.', {node: pod.fullName, tab: 'logs'}, {replace: true}); + } + }, + { + title: ( + + Delete + + ), + action: () => { + deletePodAction(pod, props.appContext, props.app.metadata.name, props.app.metadata.namespace); + } + } + ]} + /> + )) + )} +
    + ); +} + function expandCollapse(node: ResourceTreeNode, props: ApplicationResourceTreeProps) { const isExpanded = !props.getNodeExpansion(node.uid); node.isExpanded = isExpanded; props.setNodeExpansion(node.uid, isExpanded); } +function NodeInfoDetails({tag: tag, kind: kind}: {tag: models.InfoItem; kind: string}) { + if (kind === 'Pod') { + const val = `${tag.name}`; + if (val === 'Status Reason') { + if (`${tag.value}` !== 'ImagePullBackOff') + return ( + + {tag.value} + + ); + else { + return ( + + {tag.value} + + ); + } + } else if (val === 'Containers') { + const arr = `${tag.value}`.split('/'); + const title = `Number of containers in total: ${arr[1]} \nNumber of ready containers: ${arr[0]}`; + return ( + + {tag.value} + + ); + } else if (val === 'Restart Count') { + return ( + + {tag.value} + + ); + } else if (val === 'Revision') { + return ( + + {tag.value} + + ); + } else { + return ( + + {tag.value} + + ); + } + } else { + return ( + + {tag.value} + + ); + } +} + function renderResourceNode(props: ApplicationResourceTreeProps, id: string, node: ResourceTreeNode & dagre.Node, nodesHavingChildren: Map) { const fullName = nodeKey(node); let comparisonStatus: models.SyncStatusCode = null; @@ -665,25 +817,29 @@ function renderResourceNode(props: ApplicationResourceTreeProps, id: string, nod
    {node.createdAt || rootNode ? ( - - {node.createdAt || props.app.metadata.creationTimestamp} - + + + {node.createdAt || props.app.metadata.creationTimestamp} + + ) : null} {(node.info || []) .filter(tag => !tag.name.includes('Node')) .slice(0, 4) - .map((tag, i) => ( - - {tag.value} - - ))} + .map((tag, i) => { + return ; + })} {(node.info || []).length > 4 && ( ( -
    - {i.name}: {i.value} -
    - ))} + content={ + <> + {(node.info || []).map(i => ( +
    + {i.name}: {i.value} +
    + ))} + + } key={node.uid}> More @@ -776,6 +932,7 @@ export const ApplicationResourceTree = (props: ApplicationResourceTreeProps) => const [filters, setFilters] = React.useState(props.filters); const [filteredGraph, setFilteredGraph] = React.useState([]); const filteredNodes: any[] = []; + React.useEffect(() => { if (props.filters !== filters) { setFilters(props.filters); @@ -783,6 +940,18 @@ export const ApplicationResourceTree = (props: ApplicationResourceTreeProps) => props.setTreeFilterGraph(filteredGraph); } }, [props.filters]); + const {podGroupCount, userMsgs, updateUsrHelpTipMsgs, setShowCompactNodes} = props; + const podCount = nodes.filter(node => node.kind === 'Pod').length; + + React.useEffect(() => { + if (podCount > podGroupCount) { + const userMsg = getUsrMsgKeyToDisplay(appNode.name, 'groupNodes', userMsgs); + updateUsrHelpTipMsgs(userMsg); + if (!userMsg.display) { + setShowCompactNodes(true); + } + } + }, [podCount]); function filterGraph(app: models.Application, filteredIndicatorParent: string, graphNodesFilter: dagre.graphlib.Graph, predicate: (node: ResourceTreeNode) => boolean) { const appKey = appNodeKey(app); diff --git a/ui/src/app/applications/components/application-resources-diff/application-resources-diff.scss b/ui/src/app/applications/components/application-resources-diff/application-resources-diff.scss index f8208a36653a3..fb139f273a24c 100644 --- a/ui/src/app/applications/components/application-resources-diff/application-resources-diff.scss +++ b/ui/src/app/applications/components/application-resources-diff/application-resources-diff.scss @@ -6,7 +6,8 @@ text-align: right; label { padding-right: 2em; - @include themify($themes) { + color: $argo-color-gray-8; + @include themify($themes){ color: themed('text-2'); } } @@ -30,4 +31,8 @@ .custom-diff-hunk { color: $argo-color-gray-6; + border-bottom: 1px dashed; + @include themify($themes){ + border-bottom: 1px dashed themed('text-2'); + } } \ No newline at end of file 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 5842209f6e959..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 @@ -26,14 +26,15 @@ .application-status-panel { font-size: 0.875em; - @include themify($themes) { + @include themify($themes) { background-color: themed('background-2'); color: themed('text-1'); } - box-shadow: 1px 2px 3px rgba(0, 0, 0, 0.1); + box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1); flex-wrap: nowrap; flex-shrink: 1; overflow-x: auto; + padding-bottom: 0.5em; $row-width: 250px; @@ -52,38 +53,44 @@ &__more-button { margin-left: auto; - font-size: 12px; + font-size: 14px; line-height: 20px; - padding: 0; + padding: 0 5px; + cursor: pointer; + color: $argo-color-gray-6; } &__item { - height: 105px; margin-top: 5px; padding: 5px 20px; font-size: 0.8em; line-height: 1.2; - @include themify($themes) { - color: themed('text-1'); + @include themify($themes) { + color: themed('text-1'); } display: flex; flex-direction: column; + justify-content: flex-start; flex-shrink: 0; flex-grow: 0; &__row { display: flex; max-width: $row-width; + margin-bottom: 0.25em; flex-shrink: 1; div:first-child { + width: 80px; margin-right: 10px; + text-align: right; } div:last-child { font-weight: 500; - margin-left: auto; + width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + text-align: left; } @include responsive-widths(); @@ -94,7 +101,9 @@ } &:not(:first-child) { - border-left: 1px solid $argo-color-gray-3; + @include themify($themes) { + border-left: 1px solid themed('border'); + } } & { @@ -115,7 +124,7 @@ label { display: block; - @include themify($themes) { + @include themify($themes) { color: themed('text-1'); } font-size: 13px; @@ -129,12 +138,14 @@ &__item-value { display: flex; align-items: center; + margin-bottom: 0.5em; + font-weight: 500; .fa { font-size: 1em; } font-size: 2em; - @include themify($themes) { + @include themify($themes) { color: themed('text-1'); } &--highlight { @@ -161,15 +172,12 @@ &__revision { font-size: 14px; - @include themify($themes) { + @include themify($themes) { color: themed('text-1'); } font-weight: 500; - margin-left: auto; - padding-left: 5px; - a { - color: $argo-color-teal-6; - } + padding-left: 8px; + margin-bottom: 2px; } } 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 443a841f5785f..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 @@ -1,20 +1,22 @@ import {HelpIcon} from 'argo-ui'; import * as React from 'react'; -import {DataLoader} from '../../../shared/components'; +import {ARGO_GRAY6_COLOR, DataLoader} from '../../../shared/components'; import {Revision} from '../../../shared/components/revision'; import {Timestamp} from '../../../shared/components/timestamp'; import * as models from '../../../shared/models'; import {services} from '../../../shared/services'; import {ApplicationSyncWindowStatusIcon, ComparisonStatusIcon, getAppDefaultSource, getAppOperationState} from '../utils'; -import {getConditionCategory, HealthStatusIcon, OperationState, syncStatusMessage} from '../utils'; +import {getConditionCategory, HealthStatusIcon, OperationState, syncStatusMessage, helpTip} from '../utils'; import {RevisionMetadataPanel} from './revision-metadata-panel'; import './application-status-panel.scss'; interface Props { application: models.Application; + showDiff?: () => any; showOperation?: () => any; showConditions?: () => any; + showExtension?: (id: string) => any; showMetadataInfo?: (revision: string) => any; } @@ -24,26 +26,27 @@ interface SectionInfo { } const sectionLabel = (info: SectionInfo) => ( -